pattern found in vim search, but not in vim search and replace? - search

There is a search and replace operation I am trying to do using backreferencing and regular expressions in vim. Interestingly, it will only recognize the pattern if I do a pure search, but if I do a search and replace it gives me an E486: pattern not found error.
I have a bunch of function calls of the form:
function( Nullable< double >(1.1), map[FOO] );
Where FOO is some different variable name on each line. I want to turn it into
function( othermap[ FOO ], map[FOO] );
If I try
:%s/Null.*\(map[\)\(.*\)\]/othermap[ \2 \], \1\2\]/g
It gives me the "Pattern not found error." Even
:%s/Null.*\(map[\)\(.*\)\]//g
will not work because it's just not recognizing the pattern. But if I try the following command with the exact same search regex:
/Null.*\(map[\)\(.*\)\]
It highlights correctly. Following which, I can do %s//othermap[ \2 ], \1\2] to do my replacement. So I was able to do my replacement after all, but I can't for the life of me understand why the pattern would be recognized in one case and not in the other.

I can reproduce the result using copy'n'paste from your question to my vim session. The detailed message I get, though, is:
E486: Pattern not found: Null.*\(map[\)\(.*\)\]/othermap[ \2 \], \1\2\]/g
Note that it has lost the s/ at the start.
However, looking rather carefully at this, the trouble is an unescaped [:
s/Null.*\(map[\)\(.*\)\]/othermap[ \2 \], \1\2\]/g
^
|-- here; you need \[ to match the literal
I don't use the % notation; I would automatically write:
:g/Null.*\(map\[\(.*\)\]\)/s//othermap[\2], \1/g
This has slightly different capturing. There was also no need to use the backslash in \] in the replacement string.
However, this command also works for me:
:%s/Null.*\(map\[\(.*\)\]\)/othermap[\2], \1/g

Related

Can not find the good syntax for a vim sustitute pattern

I have a bunch of t_ prefixed fonction names in a header file and i would like to remove this prefix from some of them.
I have ended by typing :
:s/\(\s+\)t_\([^(]+\)(/\1\2(/c
But vim complains with Pattern not found
What is wrong in my pattern ?
You forgot to put a backslash before + to give it its quantifier meaning. You can also probably simplify it using \< to match the start of a word instead of capturing spaces.
I suggest breaking the problem down, first the search:
/\v\s+\zst_\ze.*\(
Now the substitution:
:s///\c
We can reuse a search pattern simply typing an empty search on the substitution
OBS: I suppose your functions have () at the end of the line, so .*().
Another thing; \zs and \ze to match only t_, for more see: :h \zs.
If you are using neovim you can see what happens befor hitting enter, just put these lines on your init.vim:
if has("nvim")
set inccommand=nosplit
endif

vim non-greedy unexpected behavior

I'm using vim (version 7.3).
On the following line
1xAxBx4
where A and B can be any alphanumerical character, I want to replace xBx4 with foo. I tried the following substitution command
:s/x.\{-}x4/foo/
and get 1foo instead of what I expected (1xAfoo). I can get 1xAfoo if I use this substitution command
:s/x[^A]x4/foo/
but this is too specific and won't be helpful if I want to replace on multiple lines, as "A" could be a different character on each line.
Why the unexpected behavior with \.{-}? Or is this exactly what one would expect, but I'm just misunderstanding the syntax?
Though you've correctly used the non-greedy \{-} quantifier, because there's no consumption before, it still will start matching at the first x, and then match as few as possible. Because that works, there's no backtracking.
Now, you need to add a greedy match before your expression, yet do not consume those characters. This can be achieved with \zs to let the match only start afterwards:
:s/.*\zsx.\{-}x4/foo/
this is not the use case for "non-greedy".
x.\{-}x4 will make sense for example you want to replace:
xAAAx4BBBx4CCCx4 -> ######BBBx4CCCx4
without the usage of \{-} the result would be ######
if it is known that only one single character between x and x4, you just use x.x4 or if you want to avoid space to be selected, use x\Sx4

How to do substitution only on highlighted text in vim?

Before doing substitution, I usually type /foo to search the pattern first.
Vim automatically highlight all strings match the pattern.
Then I figure out how to write the substitution command :%s/foo/bar/g.
When the pattern is complex, it's much harder to write the substitution command than the search command.
If I can do substitution only on highlighted strings. It becomes easy.
For example:
Question: Translate Part of a Line
I can figure out the search pattern: /\[\[\(http\)\#!.\{-}\]\]
But I cannot figure out the substitution command easily.
You can replace the previously searched pattern if you use an empty string as the search pattern in the substitute command:
After /foo type :%s//bar/g in normal mode to replace "foo" by "bar".
You could use the 'c' flag to tell Vim to confirm before replacing. It highlights and stops to ask before every match it finds to the given pattern.
:%s/foo/bar/gc
I just figured out:
:%s##\=substitute(submatch(0), '_', '/', '')#g
But is there any better ways?

Why do I have to escape the final ]

I have a file containing string like this one :
print $hash_xml->{'div'}{'div'}{'div'}[1]...
I want to replace {'div'}{'div'}{'div'}[1] by something else.
So I tried
%s/{'div'}{'div'}{'div'}[1]/by something else/gc
The strings were not found. I though I had to escape the {,},[ and ]
Still string not found.
So I tried to search a single { and it found them.
Then I tried to search {'div'}{'div'}{'div'} and it found it again.
Then {'div'}{'div'}{'div'}[1 was still found.
To find {'div'}{'div'}{'div'}[1]
I had to use %s/{'div'}{'div'}{'div'}[1\]
Why ?
vim 7.3 on Linux
The [] are used in regular expressions to wrap a range of acceptable characters.
When both are supplied unescaped, vim is treating the search string as a regex.
So when you leave it out, or escape the final character, vim cannot interpret a single bracket in a regex context, so does a literal search (basically the best it can do given the search string).
Personally, I would escape the opening and closing square brace to ensure that the meaning is clear.
That's because the [ and ] characters are used to build the search pattern.
See :h pattern and use the help file pattern.txt to try the following experiment:
Searching for the "[9-0]" pattern (without quotes) using /[0-9] will match every digit from 0 to 9 individually (see :h \[)
Now, if you try /\[0-9] or /[0-9\] you will match the whole pattern: a zero, an hyphen and a nine inside square brackets. That's because when you escape one of [ or ] the operator [*] ceases to exist.
Using your search pattern, /{'div'}{'div'}{'div'}[1\] and /{'div'}{'div'}{'div'}\[1] should match the same pattern which is the one you want, while /{'div'}{'div'}{'div'}[1] matches the string {'div'}{'div'}{'div'}1.
In order to avoid being caught by these special characters in regular expressions, you can try using the very magic flag.
E.g.:
:%s/\V{'div'}[1]/replacement/
Notice the \V flag at the beginning of the line.
Because the square brackets mean that vim thinks you're looking for any of the characters inside. This is known as a 'character class'. By escaping either of the square brackets it lets vim know that you're looking for the literal square string ending with '[1]'.
Ideally you should write your expression as:
%s/{'div'}{'div'}{'div'}\[1\]/replacement string/
to ensure that the meaning is completely clear.

Multiple search and replace in one line

If I do something like:
:%s/aaa/bbb/ | %s/111/222/
and the first search and replace doesn't find any matches, the second search and replace won't be executed. Is there any way to tell vim to carry on even when a command "failed"?
Try
:%s/aaa/bbb/e | %s/111/222/e
and read
:help :s_flags
especially the entry under [e]:
When the search pattern fails, do not issue an error message and, in
particular, continue in maps as if no error occurred. This is most
useful to prevent the "No match" error from breaking a mapping. Vim
does not suppress the following error messages, however:
Regular expressions can't be delimited by letters
\ should be followed by /, ? or &
No previous substitute regular expression
Trailing characters
Interrupted

Resources