I have strings like (i,1) and (i,2) in my text.
I want so search and replace them so i get
(1,i) and (2,i) respectively. How do I go about that in Vim?
:%s/(\([^,]\+\),\([^)]\+\))/(\2,\1)/g
Explanation:
: gets you into command mode
% apply the following command to each line
s the command is substitute. It consists of two parts, the pattern and the replacement. These are
seperated by /
/ Seperator for pattern. The pattern is (\([^,]\+\),\([^)]\))
( You want to match an opening paranthesis
\( store the following matching part in \1.
[^,] match anything except ,
\+ match at least one (of the not ,)
\) end the matching part for \1
, match the comma (don't store anywhere)
\( same as above, but store in \2
[^)] match anything except )
\+ match at least one (of the not ))
\) as above
) match the closing paranthesis (don't store anywhere)
/ Seperator for replacement. The replacement is (\2,\1)
( literal insertion of (
\2 insert 2nd match of pattern
, insert literal ,
\1 insert 1st match of pattern
) insert literal )
/ Seperator to indicate the end of replacement.
g so that the pattern is replaced multiple time on one line (necessary only if a line contains (bbb,ccc) multiple times)
this command does it:
%s/(\zs\([^,]*\),\([^)]*\)\ze)/\2,\1/g
or
%s/\v\(([^,]*),([^)]*)\)/(\2,\1)/g
brief explanation:
\v : very magic, to save some escapes
\( : match openning "("
([^,]*) : group 1 the text between "(" and ","
, : the comma
([^)]*) : group2 , the text between the "," and ")"
\) : ending ")"
replacement part: (\2,\1) (swap the two groups)
If you want a no-brainer, choose a macro (:help q) instead of search and replace (:help :s). I often go for macros if the search and replace patterns get complicated (e. g., they take more than one or two minutes to write). Macros are easy and intuitive, you perform your change once and simply repeat it. Solution for your problem using macros:
qq/(i,[12])<CR><SPACE>xpxp<BACKSPACE><BACKSPACE>xpq1000#q
That's 29 very easy keystrokes.
qq Record following keystrokes in register q
/(i,[12])<CR> Search for (i,1) or (i,2)
<SPACE>xpxp... Your text manipulation
q Stop recording
1000#q Replay contents from register q 1000x
Don't worry, if one of the commands fail (in this case the search for (i,1)) repetition stops immediately. Of course you can also do it the safe way:
#q Replay the keystrokes from register q (once)
## Repeat the last replay (that's easier than #q)
So you'd type something like #q######## to make the changes and check them.
Related
I have a text file in which many lines contain twice the symbol =, as in:
Animals:
clown=fish=vertebrate
cow=mammal=vertebrate
bug=insect=invertebrate
slug==snail
etc
I want to delete everything that is after the second = on each line only if the two = are not together, resulting in:
Animals:
clown=fish
cow=mammal
bug=insect
slug==snail
etc
How I can I do this?
I guess search for the second occurence of =, then select all results, then select until the end of line, then delete, but most of these steps I couldn't find a easy way to do.
This should be enough:
%s/=[^=]\+\zs=.*//
The interesting part is \zs. Look for it in the docs via :help \zs.
Beside that, I'm matching an equal sign (the first =) followed by 1 or more (\+) characters other than the equal sign ([^=]), followed by another equal sign.
Press : to go to command mode, then run this:
%s/\(\w\+=\w\+\).*/\1/g
Explanation: in entire file (%) substitute line with result from \w\+=\w\+ search pattern (one equals sign, surrounded by non-zero-length words-characters.
Since this will only match on lines where the first = is surrounded by word-characters, it won't apply to lines like slug==snail
One option is to use :normal
:%norm f=lf=D
This uses f to find the = character move to left, then search for another = using f before deleting with D. If an error occurs then that line is skipped
Is it possible to display the line count in the VIM status bar with thousands separators, preferably custom thousands separators?
Example:
set statusline=%L
should lead to "1,234,567" instead of "1234567".
I've found a way but it looks a bit crazy:
set statusline=%{substitute(line('$')\,'\\d\\zs\\ze\\%(\\d\\d\\d\\)\\+$'\,'\,'\,'g')}
The first round of backslashes is just for set (I have to escape , and \ itself).
What I'm actually setting the option to is this string:
%{substitute(line('$'),'\d\zs\ze\%(\d\d\d\)\+$',',','g')}
As a format string, this line contains one formatting code, which is %{...}. Everything in ... is evaluated as an expression and the result substituted back in.
The expression I'm evaluating is (spaces added (if I had added them to the real code, I would've had to escape them for set again, forcing yet more backslashes)):
substitute(line('$'), '\d\zs\ze\%(\d\d\d\)\+$', ',', 'g')
This is a call to the substitute function. The arguments are the source string, the regex, the replacement string, and a list of flags.
The string we're starting with is line('$'). This call returns the number of lines in the current buffer (or rather the number of the last line in the buffer). This is what %L normally shows.
The search pattern we're looking for is \d(\d\d\d)+$ (special vim craziness removed), i.e. a digit followed by 1 or more groups of 3 digits, followed by the end of the string. Grouping is spelled \%( \) in vim, and "1 or more" is \+, which gives us \d\%(\d\d\d\)\+$. The last bit of magic is \zs\ze. \zs sets the start of the matched string; \ze sets the end. This works as if everything before \zs were a look-behind pattern and everything after \ze were a look-ahead pattern.
What this amounts to is: We're looking for every position in the source string that is preceded by a digit and followed by exactly N digits (where N is a multiple of 3). This works like starting at the right and going left, skipping 3 digits each time. These are the positions where we need to insert a comma.
That's what the replacement string is: ',' (a comma). Because we're matching a string of length 0, we're effectively inserting into the source string (by replacing '' with ',').
Finally, the g flag says to do this with all matches, not just the first one.
TL;DR:
line('$') gives us the number of lines
substitute(..., '\d\zs\ze\%(\d\d\d\)\+$', ',', 'g') adds commas where we want them
%{ } lets us embed arbitrary expressions into statusline
In vim I have a line of text like this:
abcdef
Now I want to add an underscore or something else between every letter, so this would be the result:
a_b_c_d_e_f
The only way I know of doing this wold be to record a macro like this:
qqa_<esc>lq4#q
Is there a better, easier way to do this?
:%s/\(\p\)\p\#=/\1_/g
The : starts a command.
The % searches the whole document.
The \(\p\) will match and capture a printable symbol. You could replace \p with \w if you only wanted to match characters, for example.
The \p\#= does a lookahead check to make sure that the matched (first) \p is followed by another \p. This second one, i.e., \p\#= does not form part of the match. This is important.
In the replacement part, \1 fills in the matched (first) \p value, and the _ is a literal.
The last flag, g is the standard do them all flag.
If you want to add _ only between letters you can do it like this:
:%s/\a\zs\ze\a/_/g
Replace \a with some other pattern if you want more than ASCII letters.
To understand how this is supposed to work: :help \a, :help \zs, :help \ze.
Here's a quick and a little more interactive way of doing this, all in normal mode.
With the cursor at the beginning of the line, press:
i_<Esc>x to insert and delete the separator character. (We do this for the side effect.)
gp to put the separator back.
., hold it down until the job is done.
Unfortunately we can't use a count with . here, because it would just paste the separator 'count' times on the spot.
Use positive lookahead and substitute:
:%s/\(.\(.\)\#=\)/\1_/g
This will match any character followed by any character except line break.
:%s/../&:/g
This will add ":" after every two characters, for the whole line.
The first two periods signify the number of characters to be skipped.
The "&" (from what I gathered) is interpreted by vim to identify what character is going to be added.
Simply indicate that character right after "&"
"/g" makes the change globally.
I haven't figured out how to exclude the end of the line though, with the result being that the characters inserted get tagged onto the end...so that something like:
"c400ad4db63b"
Becomes "c4:00:ad:4d:b6:3b:"
I'm learning Vim and can't wrap my head around the difference between word and WORD.
I got the following from the Vim manual.
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.
A WORD consists of a sequence of non-blank characters, separated with
white space. An empty line is also considered to be a WORD.
I feel word and WORD are just the same thing. They are both a sequence of non-blank chars separated with white spaces. An empty line can be considered as both word and WORD.
Question:
What's the difference between them?
And why/when would someone use WORD over word?
I've already done Google and SO search, but their search-engine interpret WORD as just word so it's like I'm searching for Vim word vs word and of course won't find anything useful.
A WORD is always delimited by whitespace.
A word is delimited by non-keyword characters, which are configurable. Whitespace characters aren't keywords, and usually other characters (like ()[],-) aren't, neither. Therefore, a word usually is smaller than a WORD; the word-navigation is more fine-grained.
Example
This "stuff" is not-so difficult!
wwww wwwww ww www ww wwwwwwwww " (key)words, delimiters are non-keywords: "-! and whitespace
WWWW WWWWWWW WW WWWWWW WWWWWWWWWW " WORDS, delimiters are whitespace only
To supplement the previous answers... I visualise it like this; WORD is bigger than word, it encompasses more...
If I do viw ("select inner word") while my cursor is on app in the following line, it selects app:
app/views/layouts/admin.blade.php
If I do viW (WORD) while my cursor is at the same place, it selects the whole sequence of characters. A WORD includes characters that words, which are like English words, do not, such as asterisks, slashes, parentheses, brackets, etc.
According to Vim documentation ( :h 03.1 )
A word ends at a non-word character, such as a ".", "-" or ")".
A WORD ends strictly with a white-space. This may not be a word in normal sense, hence the uppercase.
eg.
ge b w e
<- <- ---> --->
This is-a line, with special/separated/words (and some more). ~
<----- <----- --------------------> ----->
gE B W E
If your cursor is at m (of more above)
a word would mean 'more' (i.e delimited by ')' non-word character)
whereas a WORD would mean 'more).' (i.e. delimited by white-space only)
similarly, If your cursor is at p (of special)
a word would mean 'special'
whereas a WORD would mean 'special/separated/words'
That's a grammar problem while understanding the definition of "word".
I get stuck at first in Chinese version of this definition (could be miss-translation).
The definition is definitely correct, but it should be read like that:
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, <EOL>).
Whitespace characters were only needed when delimiting two same types of 'word'
More examples in brackets as follow:
(example^&$%^Example) three "word" :(example), (^&$%^) and (Example)
(^&^&^^ &&^&^) two "word" : (^&^&^^) and (&&^&^)
(we're in stackoverflow) five "word" :(we), ('), (re), (in) and (stackoverflow)
Another way to say it. If ur coding, and want to move thru the line stopping at delimiters and things line that "() . [] , :" use w.
if you want to bypass those and just jump to words lets say like a novel or short story has, use W.
For coding the small w is probably the one used most often. Depends where you are in the code.
say I have this line
= function (x, y, word);
and I want to convert it to
word = function (x,y);
Thus far, I have been manually selecting the word, then 'x', and then paste it at the beginning. And then I would remove unnecessary comma.
Is there a more efficient way to accomplish the same thing?
Don't create weired functions or macros, as many advanced users may suggest you, but learn simple commands, which can help you when you would need to make similar, but slightly different substitution.
My solution would be: place cursor on the comma, and type: xxdw^Pa <C-[>
Description:
xx - delete comma and space
dw - delete word
^ - place cursor on the beginning of text in line
P - place deleted text before cursor
a - add space after word
<C-[> - escape to return to normal mode, you can also press <ESC> if you like, or don't press at all
And how to place cursor in comma? Learn about f,, F,, t,, T,, w, b and e to move faster around your text.
:%s/\(.*\),\([^)]*\)/\2\1/
EDIT:removed /g
EDIT2: the %s is only if you want to do this for the entire file. if you just want to do this for the current line then replace % with . (a dot)
I'd suggest recording a macro: (starting at the beginning of the line)
qq2f,2xdw0Pa <esc>0jq, then running that macro wherever you need it: #q.
Try this: :dw to cut the current word, move to beginning of line, then :p to paste the buffer there.
Or you could use a regular expression.
:s/\(^.*\), \(\a\+\)\();\)/\2\1\3/
(Match up to the last comma) -> \1
(match last argument) -> \2
(Match closing brace and semicolon) -> \3
The reorder the matched terms as you need.
Place cursor over word and type:
"0diw delete word and store it in register 0
dF, delete backwards up to and including ,
^ place cursor at first character in line
"0P paste word
I would suggest to map this to a key.