how to remove specific characters in vi or vim editor - vim

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

Related

Replace line in text containing special characters (mathematical equation) linux text

I want to replace a line, that represents a part of mathematical equation:
f(x,z,time,temp)=-(2.0)/(exp(128*((x-2.5*time)*(x-2.5*time)+(z-0.2)*(z-0.2))))+(
with a new one similar to the above. Both new and old lines are saved in bash variables.
Main problem is that mathematical equation is full with special characters that do not allow proper search and replace in bash mode, even when I used as delimiter special character that is not used in equation.
I used
sed -n "s|$OLD|$NEW|g" restart.k
and
sed -i "s|$OLD|$NEW|g" restart.k
but all times I get wrong results.
Any idea to solve this?
There is only * in your pattern here that is special for sed, so escape it and do replacement as usual:
sed "s:$(sed 's:[*]:\\&:g' <<<"$old"):$new:" infile
if there are more special characters in your real sample, then you will need to add them inside bracket []; there are some exceptions like:
if ^ character: it can be place anywhere in [] but not first character, because ^ character at first negates the characters within its bracket expression.
if ] character: it should be the first character, because this character is also used to end the bracket expression.
if - character: it should be the first or last character, because this character is also can be used for defining the range of characters too.

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

swapping characters in ex

I am pretty new to vim and ex and I was wondering if anyone could help me with an area I am fuzzy on. I would like to know how to swap characters on every line or occurrence of a pattern. For example How would I swap the first 2 characters of every line in a file. I know it can be done and I'm pretty sure it involves the use of parentheses to store the chars. But thats is all I know. Also, Say I wanted to replace the 2nd char on everyline with some string, how would I do that?
To replace second character in each line to r in vim: :%s/^\(.\)./\1r/:
:%s/p/r/ replace pattern p with r for all lines (because of %);
^ start line;
\( start a group;
. any character (the first in this example);
\) end the group;
. any character (the second in this example);
\1 back reference to the first group (the first character in this example);
r replacement text.
To swap two first characters: :%s/^\(.\)\(.\)/\2\1/.
Swapping the first two characters on every line:
:%s/^\(.\)\(.\)/\2\1/g
Replacing the second character on every line with "string":
:%s/^\(.\)\(.\)/\1string/g
More info on the substitute command: http://vim.wikia.com/wiki/Search_and_replace
You can do the following to swap the two first chars of every line in the buffer:
:%norm xp
or:
:%s/\v^(.)(.)/\2\1
You'll need the :global command to apply the commands above on every line matching a specific pattern:
:g/foo/norm xp
or:
:g/foo/s/\v^(.)(.)/\2\1
Reference:
:help :normal
:help :global
:help :s
:help range

How to replace in vim

I have a line in a source file: [12 13 15]. In vim, I type:
:%s/\([0-90-9]\) /\0, /g
wanting to add a coma after 12 and 13. It works, but not quite, as it inserts an extraspace [12 , 13 , 15].
How can I achieve the desired effect?
Use \1 in the replacement expression, not \0.
\1 is the text captured by the first \(...\). If there were any more pairs of escaped parens in your pattern, \2 would match the text capture between the pair starting at the second \(, \3 at the third \(, and so on.
\0 is the entire text matched by the whole pattern, whether in parentheses or not. In your case this includes the space at the end of your pattern.
Also note that [0-90-9] is the same as [0-9]: each [...] collection matches just one character. It happens to work anyway, because in your data ‘a digit followed by a space’ matches in the same places as ‘2 digits followed by a space’. (If you actually needed to only insert commas after 2 digits, you could write [0-9][0-9].)
"I have a line in a source file:..."
then you type :%s/... this will do the substitution on all lines, if it matched. or that is the single line in your file?
If it is the single line, you don't have to group, or [0-9], just :%s/ \+/,/g will do the job.
The fine answers already point interesting solutions, but here's another one,
making use of the \zs, which marks the start of the match. In this pattern:
/[0-9]\zs /
The searched text is /[0-9] /, but only the space counts as a match. Note
that you can use the class \d to simplify the digit character class, so the
following command shall work for your needs:
:s/\d\d\zs /, /g ; matches only the space, replace by `, '
You said you have multiple lines and these changes are only to certain lines.
You can either visually select the lines to be changed or use the :global
command, which searches for lines matching a pattern and applies a command to
them. Now you'd need to build an expression to match the lines to be changed
in a less precise as possible way. If the lines that begins with optional
spaces, a [ and two digits are the only lines to be matched and no other
ones, then this would work for you:
:g/\s*[\d\d/s/\d\d\zs /, /g
Check the help for pattern.txt for \ze and similar and
:global.
Homework: use the help to understand \zs and see how this works:
:s/\d\d\zs\ze /,/g

How do I capture the output of a vim command in a register, without the newlines?

This is related to this question:
How to redirect ex command output into current buffer or file?
However, the problem with using :redir is that it causes 3 or 4 extra newlines in front of the output, and they appear to be difficult to remove using the substitute function.
For example, if I do the following:
:redir #a
:pwd
:redir END
The contents of #a consist of three blank lines and then the normal expected output.
I tried to post process with something like this:
:let #b = substitute(#a, '\s*\(.\{-}\)\s*', '\1', '')
But the result is that #b has the same contents as #a.
Does anyone know a more effective (i.e. working) way to postprocess, or a replacement for :redir that doesn't have those extra lines?
The value in the b register is unchanged from the value in the a register because your regexp is failing to match.
You need to write grouping parentheses and the opening repetition brace with with backslashes.
See :help /magic; effectively, the magic option is always on for substitute() regexps.
\s only matches SP and TAB (not LF); but \_s does include LF (alternately, you could use \n to just match LF).
You need to anchor the end of the expression so that the \{-} does not “give up” without matching anything (everything but the initial newlines unmatched, and thus unreplaced from the input string).
Here is a modified version of your substitution:
:let #b = substitute(#a,'\_s*\(.\{-}\)\_s*$','\1','')
It may be simpler to just think about deleting leading and trailing whitespace instead of matching everything in between. This can be done in a single substitution by using the g substitution modifier (repeated substitutions) with a regexp that uses the alternation operator where one alternate is anchored to the start of the string (%^) and the other is anchored to the end of the string (%$).
substitute(#a,'\v%^\_s+|\_s+%$','','g')
This regexp uses \v to avoid having to add backslashes for %^, +, |, and %$.
Change both occurrences of \_s to \n if you just want to trim leading/trailing newlines (instead of SP, TAB, or NL).

Resources