swapping characters in ex - vim

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

Related

I need to replace the second occurrence of string1 by string2 on every line - vim

I know that there are multiple occurrences of string1 in every line of the file. I am looking for the shortest/quickest way to replace the second one by string2. Any method will do though vim is my preference.
You can find the second occurrence of "string1" using \zs.
Based on the :h \zs example, it will be
:%s/\(.\{-}\zsstring1\)\{2}/string2
It'll be more straightforward using external sed in Vim command mode
:%!sed 's/string1/string2/2'
See https://vi.stackexchange.com/questions/8621/substitute-second-occurence-on-line for more ways to accomplish it.
Here is one way:
:%normal 0/string1^Mncgnstring2<CR>
Breakdown:
:[range]normal <macro> executes normal mode <macro> on every line in [range],
% is a shorthand for range [<first line>,<last line>], which covers every line in the buffer,
0 is the first command of our macro, it places the cursor on the first column of the line, which is a good habit to have,
/string1^M moves the cursor to the first match for string1, the ^M is a literal <CR> obtained with <C-v><CR>,
n moves the cursor to to the next match,
cgnstring2 changes the current match to string2.
See :help :range, :help :normal, :help gn.
But it would have been more interesting to see what you tried and fix it, rather than provide you with a working solution.

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

Delete all characters after "." in each line

I have a text file with about 2,000 lines of text and I want to remove a large portion of each line of text.
The text is in this format:
Important Text that I care about. Stuff I want to delete
I am unsure as to how to delete all of the text after the . in each line.
Can someone give me a quick command that would do this?
With substitutions:
:%s/\..*/./
With :normal command:
:%norm f.lD
Various additional :normal solutions:
:%norm )Dx
:%norm $T.D
:%norm f.C.
:%norm 0/\. /e<C-v><CR>D
Use the Substitution Ex Command to Trim All Lines
This is very similar to both answers, yet I think there is value in presenting it.
Like the other answers, I just used the ex substitution command:
:%s/[^.]*$//
Explanation of substitution:
% indicates a range for all lines.
[^.] is a character class of all non-period characters
* is a quantifier indicating 0 or more matches.
$ is an anchor which communicates to VIM that we want this pattern to match at the end of the line.
Addendum
The solution assumes each line will have a period, otherwise the command will not work as expected as #Qeole has indicated. Qeole's solution addresses non-periods lines appropriately.
Use search and replace "vim feature" combined with regex:
:%s/\..*$//g
with the cursor at the first character of first line.
fS<Ctrl-V>G$d

How to delete the last word from each line in vim?

Please let me know, How I can remove the last word from each line using vim commands?
Before :
abcdef 123
xyz 1256
qwert 2
asdf 159
after :
abcdef
xyz
qwert
asdf
Similarly please let me know how to remove the second word from each line using vim command?
Use the following regex (in ex mode):
%s/\s*\w\+\s*$//
This tells it to find optional whitespace, followed by one or more word characters, followed by optional whitespace, followed by end of line—then replace it with nothing.
The question's been answered already, but here's what I'd more likely end up doing:
Record a macro:
qq to record a macro into register "q"
$ to go to the end of the line
daw to delete a word
q to stop recording
Then select the rest of the lines:
j to go down a line
vG to select to the end of the file
And apply the macro:
:norm #q
Some similar alternatives:
:%norm $daw
qq$dawjq (note the added j) then 999#q to replay the macro many times. (Macro execution stops at the first "error" -- in this case, you'd probably hit the bottom of the file, j would not work, and the macro would stop.)
The key for this is the :substitute command; it is very powerful (and often used in vi / Vim).
You need to come up with a regular expression pattern that matches what you want to delete. For the last word, that's whitespace (\s), one or more times \+ (or any number (*), depending on how you want to treat single-word lines), followed by word characters (\w\+), anchored to the end of the line ($). Note that word has a special meaning in Vim; you may want to use a different atom (e.g. \S). Voila:
:%s/\s\+\w\+$//
For the second word, you can make use of the special \zs and \ze atoms that assert for matches, but do not actually match: Anchored at the start (^), match a word, then start the match for a second one:
:%s/^\w\+\s\+\zs\w\+\s\+//
Soon, you'll also want to reorder things, not just remove them. For that, you need to know capturing groups: \(...\). The text matched by those can then be referred to in the replacement part. For example, to swap the first and second words:
:%s/^\(\w\+\s\+\)\(\w\+\s\+\)/\2\1/
For details, have a look at the help, especially :help :substitute and :help pattern.
To remove the second word from the start of a line, use the following:
:%s/^\(\s*\w\+\s\+\)\w\+\s*/\1/
Update
To treat special characters as part of the word, you have to use the \S (which matches all non-whitespace characters) instead of \w (which matches only word characters [0-9A-Za-z_]). Then, the command would be:
:%s/^\(\s*\S\+\s\+\)\S\+\s*/\1/

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