Why do I have to escape the final ] - vim

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.

Related

How to use properly the quantifier in vim?

/^[a-zA-Z0-9]{1,5}$
For example, I want to match letters or digits less than 5 in length, but the above doesn't work. In particular, it is the quantifier part is wrong.
How to correct it?
This very similar StackOverflow question has a good answer on the same topic.
Your regex isn't working because the default search pattern interpretation mode in Vim requires curly braces beginning a quantifier to be escaped. When the beginning brace isn't escaped using a slash \{, Vim searches for a literal curly brace { instead.
For example, assume we're searching the literal text: abc{1,5}
Searching with /[a-z]{1,5} matches c{1,5}
while searching with /[a-z]\{1,5} matches abc
That being said, your search pattern works when written as /^[a-zA-Z0-9]\{1,5}$ (notice the added leading slash before the quantifier opening brace). It seems like this works fine without escaping the closing brace, however I'm not sure if that will always be the case.
/\v^[a-zA-Z0-9]{1,5}$ will also work. Notice how the leading \v is used to enable "very magic" mode (see :help magic for a full explanation), and that escaping the curly brace is no longer required as a result.
Additional Info
Vim has a few different ways in which the search pattern can be interpreted. See the built-in :help magic page for a full explanation including a table of characters which need to be escaped at each "magic" level.

vi replaces with empty when searching

In vi (from cygwin), when I do searching:
:%s/something
It just replaces the something with empty string like
:%s/something// .
I've googled for a while but nothing really mentions this. Is there anything I should add to the .vimrc or .exrc to make this work?
Thanks!
In vi and vim, when you search for a pattern, you can search it again by simply typing /. It is understood that the previous pattern has to be used when no pattern is specified for searching.
(Though, you can press n for finding next occurence)
Same way, when you give a source (pattern) and leave the replacement in substitute command, it assumes that the replacement is empty and hence the given pattern is replaced with no characters (in other words, the pattern is removed)
In your case, you should understand that % stand for whole file(buffer) and s for substitute. To search, you can simply use /, followed by a pattern. To substitute , you will use :s. You need not confuse searching and substituting. Hence, no need for such settings in ~/.exrc. Also, remember that / is enough to search the whole buffer and % isnt necessary with /. / searches the entire buffer implicitly.
You may also want to look at :g/Pattern/. Learn more about it by searching :help global or :help :g in command line.
The format of a substitution in vim is as follows:
:[range]s[ubstitute]/{pattern}/{string}/[flags] [count]
In your case you have omitted the string from the substitution command and here what vim documentation stated about it:
If the {string} is omitted the substitute is done as if it's empty.
Thus the matched pattern is deleted. The separator after {pattern}
can also be left out then. Example: >
:%s/TESTING This deletes "TESTING" from all lines, but only one per line.
For compatibility with Vi these two exceptions are allowed:
"/{string}/" and "\?{string}?" do the same as "//{string}/r".
"\&{string}&" does the same as "//{string}/".
E146
Instead of the '/' which surrounds the pattern and replacement string, you can
use any other single-byte character, but not an alphanumeric
character, '\', '"' or '|'. This is useful if you want to include a
'/' in the search pattern or replacement string. Example: >
:s+/+//+
In other words :%s/something and :%s;something or :%s,something have all the same behavior because the / ; and , in the last examples are considered only as SIMPLE SEPARATOR

replacing part of regex matches

I have several functions that start with get_ in my code:
get_num(...) , get_str(...)
I want to change them to get_*_struct(...).
Can I somehow match the get_* regex and then replace according to the pattern so that:
get_num(...) becomes get_num_struct(...),
get_str(...) becomes get_str_struct(...)
Can you also explain some logic behind it, because the theoretical regex aren't like the ones used in UNIX (or vi, are they different?) and I'm always struggling to figure them out.
This has to be done in the vi editor as this is main work tool.
Thanks!
To transform get_num(...) to get_num_struct(...), you need to capture the correct text in the input. And, you can't put the parentheses in the regular expression because you may need to match pointers to functions too, as in &get_distance, and uses in comments. However, and this depends partially on the fact that you are using vim and partially on how you need to keep the entire input together, I have checked that this works:
%s/get_\w\+/&_struct/g
On every line, find every expression starting with get_ and continuing with at least one letter, number, or underscore, and replace it with the entire matched string followed by _struct.
Darn it; I shouldn't answer these things on spec. Note that other regex engines might use \& instead of &. This depends on having magic set, which is default in vim.
For an alternate way to do it:
%s/get_\(\w*\)(/get_\1_struct(/g
What this does:
\w matches to any "word character"; \w* matches 0 or more word characters.
\(...\) tells vim to remember whatever matches .... So, \(w*\) means "match any number of word characters, and remember what you matched. You can then access it in the replacement with \1 (or \2 for the second, etc.)
So, the overall pattern get_\(\w*\)( looks for get_, followed by any number of word chars, followed by (.
The replacement then just does exactly what you want.
(Sorry if that was too verbose - not sure how comfortable you are with vim regex.)

What vim pattern matches a number which ends with dot?

In PDP11/40 assembling language a number ends with dot is interpreted as a decimal number.
I use the following pattern but fail to match that notation, for example, 8.:
syn match asmpdp11DecNumber /\<[0-9]\+\.\>/
When I replace \. with D the pattern can match 8D without any problem. Could anyone tell me what is wrong with my "end-with-dot" pattern? Thanks.
Your regular expression syntax is fine (well, you can use \d instead of [0-9]), but your 'iskeyword' value does not include the period ., so you cannot match the end-of-word (\>) after it.
It looks like you're writing a syntax for a custom filetype. One option is to
:setlocal filetype+=.
in a corresponding ~/.vim/ftplugin/asmpdp11.vim filetype plugin. Do this when the period character is considered a keyword character in your syntax.
Otherwise, drop the \> to make the regular expression match. If you want to ensure that there's no non-whitespace character after the period, you can assert that condition after the match, e.g. like this:
:syn match asmpdp11DecNumber /\<\d\+\.\S\#!/
Note that a word is defined by vim as:
A word consists of a sequence of letters, digits and underscores, or a
sequence of other non-blank characters, separated with white space
(spaces, tabs, ). This can be changed with the 'iskeyword'
option. An empty line is also considered to be a word.
so your pattern works fine if whitespace follows the number. You may want to skip the \>.
I think the problem is your end-of-word boundary marker. Try this:
syn match asmpdp11DecNumber /\<[0-9]\+\./
Note that I have removed the \> end-of-word boundary. I'm not sure what that was in there for, but it appears to work if you remove it. A . is not considered part of a word, which is why your version fails.

Vim Search/replace: what do I need to escape?

I'm trying to search and replace $data['user'] for $data['sessionUser'].
However, no matter what search string I use, I always get a "pattern not found" as the result of it.
So, what would be the correct search string? Do I need to escape any of these characters?
:%s/$data['user']/$data['sessionUser']/g
:%s/\$data\[\'user\'\]/$data['sessionUser']/g
I did not test this, but I guess it should work.
Here's a list of all special search characters you need to escape in Vim: `^$.*[~)+/
There's nothing wrong with with the answers given, but you can do this:
:%s/$data\['\zsuser\ze']/sessionUser/g
\zs and \ze can be used to delimit the part of the match that is affected by the replacement.
You don't need to escape the $ since it's the at the start of the pattern and can't match an EOL here. And you don't need to escape the ] since it doesn't have a matching starting [. However there's certainly no harm in escaping these characters if you can't remember all the rules. See :help pattern.txt for the full details, but don't try to digest it all in one go!
If you want to get fancy, you can do:
:%s/$data\['\zsuser\ze']/session\u&/g
& refers to the entire matched text (delimited by \zs and \ze if present), so it becomes 'user' in this case. The \u when used in a replacement string makes the next character upper-case. I hope this helps.
Search and replace in vim is almost identical to sed, so use the same escapes as you would with that:
:%s/\$data\['user'\]/$data['session']/g
Note that you only really need to escape special characters in the search part (the part between the first set of //s). The only character you need to escape in the replace part is the escape character \ itself (which you're not using here).
The [ char has a meaning in regex. It stands for character ranges. The $ char has a meaning too. It stands for end-line anchor. So you have to escape a lot of things. I suggest you to try a little plugin like this or this one and use a visual search.

Resources