VIM how to substitute with offset - vim

The search command in vim allows you to place the cursor relative to the search results. For example, /hello/b+2 places the cursor on the first l.
How do I do that with the substitute command?
s/hello/b+2/_/
does not work.
I need this to replace not the entire search string, but a portion of it only (specifically, to blank out all but the first character of a word).

You generally have two options: similar to other regex engines zero-width matches (though with different syntax):
:s/\(he\)\#<=llo/_/
or vim-specific “set the start of the match here”:
:s/he\zsllo/_/
. Also, there is a workaround which will look similar in almost every other regex engine:
:s/\(he\)llo/\1_/
: this captures text that should be unchanged and makes replacement include it.

Related

Select first char up to first non camelCase or non upper case char or up to first snake case _ in vim

I used this map:
map ,w v/\([^ a-z0-9]\|[^ A-Z0-9]\)*<cr>h
the idea is to select
in the words
mysuperTest
MYSUPER_TEST
mysuper_test
to always select the part that says mysuper
but it doesnt work, not sure why
I would use something like the below:
nnoremap ,w v/\C\%#.\([a-z]\+\<bar>[A-Z]\+\)\zs<cr>h
One point to notice is that in a mapping you need to use <bar> (or escape | with an extra backslash) since otherwise | is recognized as a command separator (see :help map-bar.)
Another one to notice is that you want the match to start at the first character outside the word (so you'll land at the end of the word with the h). The visual selection will expand to the start of the match in a search. I suggest using \zs to set the start of the match explicitly (see :help /\zs.)
Finally, beware of 'ignorecase' or 'smartcase' settings. Use \C to explicitly request a case-sensitive match (see :help /\C.)
I also like the idea of using a stronger anchor for the start of the match, so I'm using \%# to match the current cursor position (see :help /\%#), so you're always sure to match the current word only and not end up wandering through the buffer.
Putting it all together:
\C Case-sensitive search
\%# From cursor position
. Skip first character
\( Either one of:
[a-z]\+ One or more lowercase letters
\| (\<bar>) Or:
[A-Z]\+ One or more uppercase letters
\) End group
\zs Set match position here
I'm skipping the first character under the cursor, since in a CamelCase word, the first character won't match capitalization of the remainder of the word.
I kept your original idea of finding the first character after the word then using h to go back one to the left. But that might be a problem if, for example, the word is at the end of the line.
You can actually match the last character of the word instead with something like [a-z]\+\zs[a-z], which will set the start of the match on the last lowercase character. You can do this for both sides of the group (you can have more than one \zs in your pattern, last wins.) If you structure your match that way, you won't need the final h to go back.
I didn't handle numbers, I'll leave those as an exercise to the reader.
Finally, consider there are quite a few corner cases that can make such a mapping quite tricky to get right. Rather than coming up with your own, why not look at plug-ins which add support for handling CamelCase words that have been battle-tested and will cover use cases a lot more advanced than the simple expression you're using here?
There's the excellent vim-scripts/camelcasemotion by Ingo Karkat which sets up a ,w mapping to move to the start of the next CamelCase word, but also i,w to select the current one. You can use powerful combinations such as v3i,w to visually select the current and next two CamelCase words.
You might also check Tim Pope's tpope/vim-abolish which, among other features, defines a set of cr mappings to do coercion from camelCase to MixedCase, snake_case, UPPER_CASE, etc. (Not directly about selecting them, but still related and you might find it useful.)

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

What does \#<= and \#= mean in Vim command?

Can't understand \#<= and \#= Benoit's answer of this post, anyone can help explain them?
From vim documentation for patterns
\#= Matches the preceding atom with zero width. {not in Vi}
Like "(?=pattern)" in Perl.
Example matches
foo\(bar\)\#= "foo" in "foobar"
foo\(bar\)\#=foo nothing
*/zero-width*
When using "\#=" (or "^", "$", "\<", "\>") no characters are included
in the match. These items are only used to check if a match can be
made. This can be tricky, because a match with following items will
be done in the same position. The last example above will not match
"foobarfoo", because it tries match "foo" in the same position where
"bar" matched.
Note that using "\&" works the same as using "\#=": "foo\&.." is the
same as "\(foo\)\#=..". But using "\&" is easier, you don't need the
braces.
\#<= Matches with zero width if the preceding atom matches just before what
follows. |/zero-width| {not in Vi}
Like '(?<=pattern)" in Perl, but Vim allows non-fixed-width patterns.
Example matches
\(an\_s\+\)\#<=file "file" after "an" and white space or an
end-of-line
For speed it's often much better to avoid this multi. Try using "\zs"
instead |/\zs|. To match the same as the above example:
an\_s\+\zsfile
"\#<=" and "\#<!" check for matches just before what follows.
Theoretically these matches could start anywhere before this position.
But to limit the time needed, only the line where what follows matches
is searched, and one line before that (if there is one). This should
be sufficient to match most things and not be too slow.
The part of the pattern after "\#<=" and "\#<!" are checked for a
match first, thus things like "\1" don't work to reference \(\) inside
the preceding atom. It does work the other way around:
Example matches
\1\#<=,\([a-z]\+\) ",abc" in "abc,abc"

How to share searchText between vim search and vim substitute?

When i need to replace a string with a new string in vim.
First i would use search-mode to check that the search pattern is correct.
/search pattern
Then use the 's' command to do substitution.
:%s/search pattern/new string/
The search pattern need to type twice. If it is too complex, it would be boring.
Is there a method to avoid this?
You can simply omit the pattern in the substitution command, e.g.
:%s//new string/
This is documented in :help last-pattern (emphasis mine):
The last used pattern and offset are remembered. They can be used to
repeat the search, possibly in another direction or with another
count. Note that two patterns are remembered: One for 'normal' search
commands and one for the substitute command ":s". Each time an empty
pattern is given, the previously used pattern is used.
Also (in addition to Marco Baldelli's correct answer), the last search pattern is stored in the special register /. You can insert this in the command-line via Ctrl + R, followed by /. (This also works in insert mode, and also with other registers.) It's helpful when you want to tweak your search pattern before substituting.

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.)

Resources