How to remove space gap when using & symbol in vim - linux

I want to add "caps" at the end of all words ending with "w".
For example "jaw" should become "jawcaps", and "blow" should become "blowcaps"
The following command is using regular expression for achieving upper requirement.
:%s/[A-Za-z][A-Za-z]*w[^A-Za-z]/&caps
But when I use the command above "jaw" converts into "jaw caps" not "jawcaps"
How can I remove the space which is located between "jaw" and "caps"?

How about this:
:%s/w\>\zs/caps/g

You have a problem in your regex, your regex would match a non character after the value w. In your case, match jaw[one space] instead of jaw
:%s/[A-Za-z][A-Za-z]*w[^A-Za-z]/&caps
^^^ here match a space
I suggest you to use a capture regex.
:%s/\([A-Za-z][A-Za-z]*w\)\([^A-Za-z]\)/\1caps\2
A better solution should be using look behind.
:%s/\w\w*w\w\#!/&caps

Sato Katsura's answer :%s/w\>\zs/caps/g works like this:
Search for every place where a "w" character is the last character of a word: /w\>.
But don't match that "w": only a zero-width space after the "w" should be matched: /w\>\zs (or /w\zs\>).
Replace that match with the word "caps": s/w\>\zs/caps/.
Do so on every line: range is %, and on every occurrence on those lines: flag is g.
Putting it together: :%s/w\>\zs/caps/g.
match word end :h /\>
set match start :h \zs
substitution command :h :s
range specification :h :range
substitution flags :h :s_flags

Related

how to remove specific characters in vi or vim editor

I have some txt in vi:
|NC_004718|29751nt|SARS
|NC_045512|29903nt|Severe
|NC_004718|29751nt|SARS
|NC_045512|29903nt|Severe
|NC_004718|29751nt|SARS
now I want to replace remove everything after NC_004718, my expected output is:
NC_004718
NC_045512
NC_004718
NC_045512
NC_004718
How to do it? Thanks.
I would recommend using a substitution with regular expression to match the entire string and to capture what you would like to keep in parentheses. That way you can then replace the entire string with just the match.
:%s/^|\([^|]\+\)|.\+/\1/
To break down what is happening:
% means that you want to apply the command to each line within the file.
s means that you are doing substitution command (on each line). The s command has a syntax of s/<regular expression pattern>/<replacement>/<flags>
The regular eression pattern in the above command is ^|\([^|]\+\)|.\+.
^ means match from the line start.
| matches the character |.
\([^|]\+\) matches all characters except for the character |. Note that the real regular expression is actually ([^|]+), the additional \ characters are there because Vim needs to know that they are intended to be special characters for processing and not exact characters it needs to match. Also note that the parentheses are there to capture the match into a group (see below).
| again matches the actual character |.
.\+ matches all characters until the end of the line. Note that the . is considered special character by default but + still needs a preceding \.
The replacement text is only \1. This denotes that Vim should replace the text with whatever was captured in the first group (i.e. the first set of parentheses).
There are no flags with this command so there is nothing after the last /.
For example,
:g/NC_\d\+/normal! ygnV]p
:g/regex/ to match lines
normal! to execute Normal mode commands
ygn to yank the text previously matched by :g
V to select the whole line
]p or p to replace the line with the match
If you have only lines like those you have shown try:
:%norm xf|D

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

How to pad strings inside curly braces with odd number of character with a single space?

We have many \foo{something}. As the string inside the curly braces contains odd number of character, we want to add a space after the string. The result will be \foo{something }. We only want odd number of characters only. For example, in \foo{string} the string inside the curly braces has even number of character, then we do not add a space.
What I have tried:
a dot means a character, two dots means two characters
asterisk means repeat 0 or more times
Then, [..]*. means 1, 3, 5 ... characters.
Then, \foo{[..]*.} will be my matching sequence.
Then, :%s/\foo{[..]*.}/\foo{[..]*. }/g will add the space we want.
But we failed.
This cmd should do:
:%s/\\foo{\zs[^}]\+\ze}/\=substitute(submatch(0), '$', len(submatch(0))%2?' ':'','g')/
:%s/\\\w\+{\([^}]\{2}\)*[^}]\zs\ze}/ /g
Explanation:
Find pairs of characters (\([^}]\{2}\)*) followed by another character ([^}]) in between a macro \\\w\+{...}. Then do a substitution adding an additional space.
Glory of details:
\\\w\+{...} find macros of the pattern \foo{...}
Look for character that does not match an ending curly brace, [^}]
Look for pairs of non-}'s, \([^}]\{2}\)*
Find an odd length string by finding pairs and then finding one more, \([^}]\{2}\)*[^}]
Use \zs and \ze to set where the start and end of the match
Use a space in the replacement portion of the substitution to add additional space and thereby making the string even in length
Fore more help see:
:h :s
:h :range
:h /\[]
:h /\(
:h /\zs
:h /\w
:h /star
:h /\+
This should work
:%s/\v[(\{(\w{2})*) ]#<!}/ }/g
break down:
%s " run substitute on every line
\v " very magic mode
[(\{(\w{2})*) ] " matches every `{` followed by an equal number of word
characters and space, since you don't want to add a space again everytime
you run it.
#<!} " negative lookahead, matches all } not following the pattern before
Update
To solve the precise problem as you can read in the comments, the following command helps.
g/^\\foo/s/\v(\{([^}]{2})*)#<!}/ }/g
Changes:
g/^\\foo/... " only run it on lines starting with \foo
[^}] " it does now match all characters between { and } not only word
characters.
Pitfalls: won't work correct with multiple braces on the line ( \foo{"hello{}"} and \foo{string} {here it would also match} f.e. will fail). if one of these is a problem. just tell me

Find and replace only part of a single line in Vim

Most substitution commands in vim perform an action on a full line or a set of lines, but I would like to only do this on part of a line (either from the cursor to end of the line or between set marks).
example
this_is_a_sentence_that_has_underscores = this_is_a_sentence_that_should_not_have_underscores
into
this_is_a_sentence_that_has_underscores = this is a sentence that should not have underscores
This task is very easy to do for the whole line :s/_/ /g, but seems to be much more difficult to only perform the replacement for anything after the =.
Can :substitution perform an action on half of a line?
Two solutions I can think of.
Option one, use the before/after column match atoms \%>123c and \%<456c.
In your example, the following command substitutes underscores only in the second word, between columns 42 and 94:
:s/\%>42c_\%<94c/ /g
Option two, use the Visual area match atom \%V.
In your example, Visual-select the second long word, leave Visual mode, then execute the following substitution:
:s/\%V_/ /g
These regular expression atoms are documented at :h /\%c and :h /\%V respectively.
Look-around
There is a big clue your post already:
only perform the replacement for anything after the =.
This often means using a positive look-behind, \#<=.
:%s/\(=.*\)\#<=_/ /g
This means match all _ that are after the following pattern =.*. Since all look-arounds (look-aheads and look-behinds) are zero width they do not take up space in the match and the replacement is simple.
Note: This is equivalent to (?<=...) in perl speak. See :h perl-patterns.
What about \zs?
\zs will set the start of a match at a certain point. On the face this sounds exactly what is needed. However \zs will not work correctly as it matches the pattern before the \zs first then the following pattern. This means there will only be one match. Look-behinds on the other hand match the part after \#<= then "look behind" to make sure the match is valid which makes it great for multiple replacement scenario.
It should be noted that if you can use \zs not only is it easy to type but it is also more efficient.
Note: \zs is like \K in perl speak.
More ways?!?
As #glts mentioned you can use other zero-width atoms to basically "anchor" your pattern. A list of a few common ways:
\%>a - after the 'a mark
\%V - match inside the visual area
\%>42c - match after column 42
The possible downside of using one of these methods they need you to set marks or count columns. There is nothing wrong with this but it means the substitution will maybe affected by side-effects so repeating the substitution may not work correctly.
For more help see:
:h /\#<=
:h /zero-width
:h perl-patterns
:h /\zs

An easy way to center text between first and last non-white word in vim?

Is there an easy way using a macro or ~10 line function (no plugin!) to center some text between the first and last word (=sequence of non-blank characters) on a line? E.g. to turn
>>> No user serviceable parts below. <<<
into
>>> No user serviceable parts below. <<<
by balancing the spaces +/-1? You can assume no tabs and the result should not contain tabs, but note that the first word may not start in column 1. (EDIT: ... in fact, both delimiter words as well as the start and end of the text to center may be on arbitrary columns.)
source this function:
fun! CenterInSpaces()
let l = getline('.')
let lre = '\v^\s*\S+\zs\s*\ze'
let rre = '\v\zs\s*\ze\S+\s*$'
let sp = matchstr(l,lre)
let sp = sp.matchstr(l,rre)
let ln = len(sp)
let l = substitute(l,lre,sp[:ln/2-1],'')
let l = substitute(l,rre,sp[ln/2:],'')
call setline('.',l)
endf
note
this function might NOT work in all cases. I just wrote it quick for usual case. this is not a plugin after all
the codes lines could be reduced by combining function calls. but i think it is clear in this way, so I just leave it like this.
if it worked for you, you could create a map
it works like this: (last two lines I typed #: to repeat cmd call)
You can use the :s command with the \= aka sub-replace-expression.
:s#\v^\s*\S+\zs(\s+)(.{-})(\s+)\ze\S+\s*$#\=substitute(submatch(1).submatch(3),'\v^(\s*)(\1\s=)$','\1'.escape(submatch(2),'~&\').'\2','')#
Overview
Capture the text (including white-space) between the >>> and <<< marks. Divide up the white-space on both sides of the text in half and substitute in the non-white-space text in between. This white-space balancing act is done via the regex engine's backtracking because math is hard. Lets go shopping!
Notes:
using \v or very magic mode to reduce escaping as this command is long enough
already
use # as an alternative separator instead of the usual / for :s/pat/sub/ in hopes to make it slightly more readable
Matching Pattern
:s#\v^\s*\S+\zs(\s+)(.{-})(\s+)\ze\S+\s*$#...
:s with no range supplied only do the substitution on the current line.
^\s*\S+ match the starting white-space followed by non-white-space. >>> in this case.
(\s+)(.{-})(\s+) match white-space followed by the "text" followed by white-space
3 capture groups: 1) leading white-space, 2) the "text", and 3) trailing white-space. These will be later referenced by submatch(1), submatch(2), and submatch(3) respectively
.{-} is vim-speak for non-greedy matching or .*? in perl-speak
without the non-greedy matching the second capture group would include too much white-space at its end
\S+\s*$ match the non-white-space (i.e. <<<) and any trailing white-space
Use \zs and ze to designate the start and end of the match to be replaced
Replacement
\=substitute(submatch(1).submatch(3),'\v^(\s*)(\1\s=)$','\1'.escape(submatch(2),'~&\').'\2','')
\= tells vim that replacement will be a vim expression. Also allows the use of submatch() functions
substitute({str}, {pat}, {sub}, {flags}) Our expression will be a nested substitution
substitute(submatch(1).submatch(3), ...) do a substitute over the concatenation of leading and trailing white-spacing captured in submatch(1) and submatch(3)
The {pat} is ^(\s*)(\1\s=)$. Match some white-space followed by white-space of the same length as the first or 1 character longer. Capture both halves.
escape(submatch(2),'~&\') escape submatch(2) for any special characters. e.g. ~,&,\1, ...
The {sub} is '\1'.escape(submatch(2),'~&\').'\2'. Replace with the the escaped submatch(2) (i.e. the "text" we want to center) in between the halves of white-space, \1 and \2 from the {pat}
No {flag}'s are needed so ''
Usage
If you use this often I would suggest creating a command and putting it in ~/.vimrc.
command! -range -bar -nargs=0 CenterBetween <line1>,<line2>s#\v^\s*\S+\zs(\s+)(.{-})(\s+)\ze\S+\s*$#\=substitute(submatch(1).submatch(3),'\v^(\s*)(\1\s=)$','\1'.submatch(2).'\2','')#`
Otherwise use this once and then repeat the last substitution via & on each needed line.
For more help see
:h :s/
:h :s/\=
:h sub-replace-\=
:h submatch(
:h substitute(
:h escape(
:h /\v
:h /\S
:h /\{-
:h /\zs
:h &
EDIT by Kent
Don't be jealous, your answer has it too. ^_^
I didn't change the command, just cp/paste to my vim. only add |noh at the end to disable highlighting.
If execute this command, it looks like:
I don't know of any good way. I usually do it in a semi-automatic way, by using :center on a line of text that only contains the parts that are to be centered and then move the result into the line containing the surrounding parts.
If nobody else has a better answer, perhaps boxes can help if you need to do this kind of thing a lot.

Resources