Totte Karlsson
Totte Karlsson

Reputation: 1341

A VIM search/replace pattern

How do I do a VIM search/replace with the following conditions:

a) the line contains str1

b) the line also contain str2

c) the line do NOT contain str3

on such a line, I do want to replace xxx with yyy

Upvotes: 1

Views: 2212

Answers (3)

244an
244an

Reputation: 1589

I think @Kent's answer (the function) is the "most correct" when doing complex searches/substitutions. It's easier to change afterward, and to understand it also after a while, it's also quicker to write than this. But I think it can be interesting if it's possible to do this with a "oneliner".
I welcome comments about this not working, I find it interesting myself if it's possible, not if it's the "best solution".

A "oneliner" for all situations described in the original question.

:v/str3/s/\v(.*str1&.*str2)@=.{-}\zsxxx/yyy/g

Explanation:

  • :v/str3/ all lines NOT containing "str3"
  • s/ substitute
  • \v "very magic" (to not have to escape regex expressions like {}), :h \v
  • (.*str1&.*str2)@= positive look-ahead, :h \@=
    • .*str1 any character 0 or more ("greedy") followed by "str1", the preceding .* is important for both & and @= to work
    • & pattern before and after & must be present, different than | that is using "or", both patterns must start at same place, thats why .* is used before str1/2, :h \&
    • @= the atom before (in the parentheses) should be present, but the pattern is not included in the match, the atom must however start at the beginning of the line for this to work (.* makes sure of that).
  • .{-} any character 0 or more ("not greedy"), {-} instead of * is important if more than one occurrence of xxx should be substituted (not enough with the g flag in this case)
  • \zs sets the start of the match (what to substitute).
  • xxx finally, the string to substitute
  • /yyy/ replace the match with yyy
  • g all occurences on the line

This gives the same result as using the example in @Kent's answer, it will handle any order of str1, str2, str3 and xxx.
I repeat that this is an alternative if for some reason a function is not an alternative. As I understand OP, e.g. str2 is always after str1 in his case, so this is more a general solution for situations like this (and perhaps more of academic interest).

Upvotes: 0

Kent
Kent

Reputation: 195239

regex doesn't handle and, not very well. there are ways to do it, but bit tricky. A very simple function could solve your problem:

function! Rep()
        let l = getline('.')
        if stridx(l, 'str1')>=0 && stridx(l,'str2') >=0 && stridx(l,'str3')<0
                execute 's/xxx/yyy/g'
        endif
endfunction

you can

  • either write it in your .vimrc file.
  • or save it in a foo.vim file and open it with vim type :so %

then open your target file, type :%call Rep() you will see for example:

str1 str2 str3 xxx
str3 str2 xxx
str2 xxx
*str1 str2 xxx
*xxx str2 xxx str2 xxx str1

would be changed into:

str1 str2 str3 xxx
str3 str2 xxx
str2 xxx
*str1 str2 yyy
*yyy str2 yyy str2 yyy str1

I think replacing str1,str2,xxx,yyy to your real values in that function isn't hard for you, is it?

EDIT

your real problem seems to be much easier than the problem you described in question. try this line:

:%s/\(\s*return\s*aLib\.[^(]\+(\)\s*\()\)/\1aHandle\2/

Note that it could be written shorter only for your example working, but I want it to be secure.

Upvotes: 1

user1655874
user1655874

Reputation:

This will replace the () string in every line of a file containing the string return and the string aLib at some point after that:

:%s/return.*aLib.*\zs()\ze/(aHandle)/

The % is the operating range of the command, which includes all lines in the file.

\zs denotes the start of the replaced string and \ze denotes its end.

If you have to replace more than one instance per line, put a g at the end of the command after the last /. If you wish to confirm each substitution, put the c flag at the end.

By assuming the () string is never present if aHandle is present, this command doesn't answer your question exactly, but based on the sample provided in the comments, this may match your needs.

Upvotes: 1

Related Questions