Reputation: 1341
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
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 lineThis 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
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
.vimrc
file. 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
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