VIM - 查找, 替换中的模式和正则表达式的关系

一.  正则表达式

vim中正则表达式得到了十分广泛的应用。 最常用的/ 和 :s 命令中,正则表达式都是不可或缺的。 下面对vim中的正则表达式的一些难点进行说明。

关于magic

vim中有个magic的设定。设定方法为:

:set magic " 设置magic 
:set nomagic " 取消magic 
:h magic " 查看帮助

vim毕竟是个编辑器,正则表达式中包含的大量元字符如果原封不动地引用(像perl 那样), 势必会给不懂正则表达式的人造成麻烦,比如 /foo(1) 命令, 大多数人都用它来查找foo(1)这个字符串, 但如果按照正则表达式来解释,被查找的对象就成了 foo1 了。

于是,vim就规定,正则表达式的元字符必须用反斜杠进行转义才行, 如上面的例子,如果确实要用正则表达式,就应当写成/foo\(1\) 。 但是,像. * 这种极其常用的元字符,都加上反斜杠就太麻烦了。 而且,众口难调,有些人喜欢用正则表达式,有些人不喜欢用……

为了解决这个问题,vim设置了 magic 这个东西。简单地说, magic就是设置哪些元字符要加反斜杠哪些不用加的。 简单来说:

magic (\m):除了$ . * ^ 之外其他元字符都要加反斜杠。
nomagic (\M):除了 $ ^ 之外其他元字符都要加反斜杠。
这个设置也可以在正则表达式中通过 \m \M 开关临时切换。 \m 后面的正则表达式会按照 magic 处理,\M 后面的正则表达式按照 nomagic 处理, 而忽略实际的magic设置。
/\m.* # 查找任意字符串 
/\M.* # 查找字符串 .* (点号后面跟个星号)
另外还有更强大的 \v 和 \V\v (即 very magic 之意):任何元字符都不用加反斜杠\V (即 very nomagic 之意):任何元字符都必须加反斜杠例如:
/\v(a.c){3}$ # 查找行尾的abcaccadc 
/\m(a.c){3}$ # 查找行尾的(abc){3} 
/\M(a.c){3}$ # 查找行尾的(a.c){3} 
/\V(a.c){3}$ # 查找任意位置的(a.c){3}$
默认设置是 magicvim也推荐大家都使用magic的设置,在有特殊需要时,直接通过\v\m\M\V 即可。

量词

本文下面使用的元字符都是 magic模式(除了$ . * ^ 之外其他元字符都要加反斜杠)下的,在very magic模式下,只需要将\\去掉即可.
vim 意义
* 匹配0个或多个(匹配优先)
\+ 匹配1个或多个(匹配优先)
\? 或 \= 0个或1个(匹配优先),\? 不能在?命令中使用
\{n,m} 匹配n个到m个, 如\d{1, 3}可以匹配13个数字,类似111333
\{n,} 最少n个(匹配优先)
\{,m} 最多m个(匹配优先)
\{n} 恰好n
 在这里,有些东西需要说明一下,那就是上面的用于限定数量的元字符不单单可以用于字符,同时也可以用于模式,举个例子,下面的模式:
\(123\)\{2}
 可以匹配123123.

 一些常用的元字符

元字符说明
. 匹配任意一个字符,如p*p可以匹配字符串pep, pip或者pcp
[abc] 匹配方括号中的任意一个字符。可以使用-表示字符范围
[a-z0-9] 匹配小写字母和阿拉伯数字
[^abc] 在方括号内开头使用^符号,表示匹配除方括号中字符之外的任意字符
\d 匹配阿拉伯数字,等同于[0-9]
\D 匹配阿拉伯数字之外的任意字符,等同于[^0-9]
\x 匹配十六进制数字,等同于[0-9A-Fa-f]
\w 匹配单词字母,等同于[0-9A-Za-z_]
\W 匹配单词字母之外的任意字符,等同于[^0-9A-Za-z_]
\t 匹配<TAB>字符
\s 匹配空白字符,等同于[ \t]
\S 匹配非空白字符,等同于[^ \t]
\a 所有的字母字符. 等同于[a-zA-Z]
\l 小写字母[a-z]
\L 非小写字母[^a-z]
\u 大写字母 [A-Z]
\U 非大写字幕[^A-Z]

元字符的转义:

\* 匹配 * 字符
\. 匹配 . 字符
\/ 匹配 / 字符
\\ 匹配\字符
\[ 匹配 [ 字符

表示位置的符号

位置元字符含义
$ 匹配行尾,如here:$只会匹配出位于一行结尾的here:.
^ 匹配行首,如^Part只会匹配出位于一行开头的Part.
\< \> 会匹配出以某些字符开头的(\<)或结尾(\>)的单词.\<ac只会匹配出以ac开头的单词,如action,而ac>/只会匹配出以ac结尾的单词,如maniac.\<action\>会匹配出action这个单词.单词的开头和结尾,是用标点符号或空格来分隔的.

替换变量

在正规表达式中使用 \(\) 符号括起正规表达式,即可在后面使用\1\2等变量来访问 \(\) 中的内容。这种形式实际上是将\(\)中的模式保存到了特殊的空间(称之为"保留缓冲区").这种方法可以保存任意一行中的9个模式.举个例子,对于下面的模式:
\(That\) or \(this\)
会将That存放到缓冲区1中,而将this保存到保留缓冲区2中,这些保留的模式在以后可以用\1\9的序列重新排列,例如,如果要将That or this改成this or That,可以键入:
:%s/\(That\) or \(this\)/\2 or \1/
也可以实现在搜索或者替换字符串时使用\n表示法:
:%s\(abcd\)\1/alphabet-soup/
可以将abcdabcd替换为alphabet-soup.这里需要特别注意一下,\0表示我们所匹配的所有内容.

非贪婪匹配

非贪婪匹配也是正则表达式中一个非常强大的特性,我这里稍微来记录一下vim中非贪婪匹配的语法.
假设我有这样一段文本:
map<wstring, wstring> grammarTokens = {
    {L"_LPAR", L"\\("},
    {L"_RPAR", L"\\)"},
    {L"_LBRA", L"\\["},
    {L"_RBRA", L"\\]"},
    {L"OP", L"[+?]"},
    {L"_COLON", L":"},      // 冒号
    {L"_OR", L"\\|"},
    {L"_DOT", L"\\."},
    {L"RULE", L"!?[_?]?[a-z][_a-z0-9]*"},  // 用于表示普通的规则
    {L"TOKEN", L"_?[A-Z][_A-Z0-9]*"},
    {L"REGEXP", L"/(?!/)(\\/|\\\\|[^/\n])*?/i?"},
    {L"_NL", L"(\r?\n)+\s*"},
    {L"WS", L"[\t]+"},
    {L"COMMENT", L"//[^\n]*"},
    {L"_TO", L"-->"},
    {L"_IGNORE", L"%ignore"},
    {L"_IMPORT", L"%import"}
};
上面的这段c++代码片段实际上是存在错误的,要将所有的字符都变成这样wstring(L"xxxx"),才能消除错误,所以,我们想到了,正则表达式正好可以用来干这个事情.最开始的时候,我使用的是这种语法:
:%s/\(L".*"\)/wstring(\1)/g
结果很有意思:
map<wstring, wstring> grammarTokens = {
    {wstring(L"_LPAR", L"\\(")},
    {wstring(L"_RPAR", L"\\)")},
    {wstring(L"_LBRA", L"\\[")},
    {wstring(L"_RBRA", L"\\]")},
    {wstring(L"OP", L"[+?]")},
    {wstring(L"_COLON", L":")},     // 冒号
    {wstring(L"_OR", L"\\|")},
    {wstring(L"_DOT", L"\\.")},
    {wstring(L"RULE", L"!?[_?]?[a-z][_a-z0-9]*")},  // 用于表示普通的规则
    {wstring(L"TOKEN", L"_?[A-Z][_A-Z0-9]*")},
    {wstring(L"REGEXP", L"/(?!/)(\\/|\\\\|[^/\n])*?/i?")},
    {wstring(L"_NL", L"(\r?\n)+\s*")},
    {wstring(L"WS", L"[\t]+")},
    {wstring(L"COMMENT", L"//[^\n]*")},
    {wstring(L"_TO", L"-->")},
    {wstring(L"_IGNORE", L"%ignore")},
    {wstring(L"_IMPORT", L"%import")}
};

这个显然是超乎我们预期的,原因在于正则表达式中.*是贪婪匹配,什么意思呢,也就是说,这个表达式会一直向前匹配,匹配尽可能多的文本.
{L"_LPAR", L"\\("}这一行为例,用\(L".*"\)来进行匹配的时候,L匹配L, "匹配",然后.可以匹配任意的字符,*代表重复零次或者多次,因此,这里匹配了_LPAR,虽然下一个"可以和正则式的"相匹配,如果此时停下来,是完全合理的,但是所谓的贪婪,就体现在了这里,我要一直尝试,一定要匹配更多的字符,所以继续前进,.*匹配了_LPAR",L"\\(,一直到下一个",正则表达式发现如果我继续用.*来匹配掉"的话,那么在这一行,我的匹配会失败,所以不能继续了,所以用正则表达式中的"匹配",匹配成功.

你可能会疑问,为什么.*不匹配到下一行,下下行,我只能说,vim的正则表达式是一行一行进行匹配的.

所以人们为了避免这种情况,提出了一个非贪婪匹配的概念,核心是,匹配尽可能少的字符.

所以在这里,我们要将其替换为非贪婪匹配,非贪婪匹配的语法很奇葩,是这样的\{-},我们要将前面的.*变成.\{-},所以命令变成了:

:%s/\(L".\{-}"\)/wstring(\1)/g

或者使用very magic模式,也可以达到同样的效果:

:%s/(L.{-})/wstring(\1)/g
结果非常漂亮:
map<wstring, wstring> grammarTokens = {
    {wstring(L"_LPAR"), wstring(L"\\(")},
    {wstring(L"_RPAR"), wstring(L"\\)")},
    {wstring(L"_LBRA"), wstring(L"\\[")},
    {wstring(L"_RBRA"), wstring(L"\\]")},
    {wstring(L"OP"), wstring(L"[+?]")},
    {wstring(L"_COLON"), wstring(L":")},        // 冒号
    {wstring(L"_OR"), wstring(L"\\|")},
    {wstring(L"_DOT"), wstring(L"\\.")},
    {wstring(L"RULE"), wstring(L"!?[_?]?[a-z][_a-z0-9]*")},  // 用于表示普通的规则
    {wstring(L"TOKEN"), wstring(L"_?[A-Z][_A-Z0-9]*")},
    {wstring(L"REGEXP"), wstring(L"/(?!/)(\\/|\\\\|[^/\n])*?/i?")},
    {wstring(L"_NL"), wstring(L"(\r?\n)+\s*")},
    {wstring(L"WS"), wstring(L"[\t]+")},
    {wstring(L"COMMENT"), wstring(L"//[^\n]*")},
    {wstring(L"_TO"), wstring(L"-->")},
    {wstring(L"_IGNORE"), wstring(L"%ignore")},
    {wstring(L"_IMPORT"), wstring(L"%import")}
};
错误消除.

环视,或者说正向预查,反向预查

在各种常用工具对比中,我看到vim是支持计数的,而且似乎大部分常用的正则元字符都与perl兼容,比如\s,\d,\D,\w,\W, < >。但vim不支持\b,即单词边界。另外,vim中比较麻烦的是它似乎支持的是BRE(基本正则表达式,posix定义的),BRE中所有括号都不是元字符,因为作为元字符的是\(,\{。比如vim中匹配连续39,你得用9\{3\},原来我一直以为不支持,但我还是觉得麻烦了一点,grep默认也是使用的这种BRE
perl相比,vim(?换成了\@,并且这个符号应该跟在匹配模式的后边。下面是一组对比:
vimPerl意义例子
\@= (?= 顺序环视 查找后面是sqlmy/my\(sql\)\@=
\@! (?! 顺序否定环视 查找后面不是sqlmy/my\(sql\)\@!
\@<= (?<= 逆序环视 查找前面是mysql/\(my\)\@<=sql
\@<! (?<! 逆序否定环视 查找前面不是mysql/\(my\)\@<!sql
\@> (?> 固化分组  
\%(atom\) (?: 非捕获型括号(此分组不捕获,可以理解为不算在分组信息中) :%s/\%(my\)sql\(ok\)/\1这个命令会将mysqlok替换为 ok ,由于my为捕获在分组中,故组中\1ok

正如前面所说的,如果使用very magic模式的话,这些命令都将大大简化,因为我们可以省略掉大量的转义字符,以:%s/\%(my\)sql\(ok\)/\1为例,它可以替换成%s/\v%(my)sql(ok)/\1,是不是清晰很多了呢.

二.  常用的替换命令

删除所有的空白行

:g/^$/d

 vim中的四种pattern

 

 

 

 {only Vim supports \m, \M, \v and \V}
     建议始终将 'magic' 选项保持在缺省值 -  'magic'。这可以避免移植性的麻烦。要使模式不受该选项值的影响,在模式前面加上 "\m" 或 "\M".

pattern和正则之间的关系

1.   \v模式   (v小写)

如在vim中查找字符$,如果使用\v模式,则写作:

:/\v\$

而不是:

:/\v$

即在\v模式下,   $       .(句点)     *     (        {         等都被看作是正则表达式中的特殊字符,要匹配本身,需要加反斜杠\。

2.  \m模式

如果在vimrc等配置文件中设置了set matic则默认查找替换等时采用此模式。

如果在vim中查找字符{,如果使用\m模式,则写作:

:/\m{

但是,若在\v模式下,则写作:

:/\m\{

 

建议:为了和正则匹配,建议用\v(v小写)模式!

PS:替换中,[range]/pattern/string/[c,g,e,i]      

  string不存在模式和正则的问题,sting所见即所得。

 

三.  vim 全文替换的几种写法

%s/aaa/bbb/g
.,$s/aaa/bbb/g
,$s/aaa/bbb/g
1,$s/aaa/bbb/g
s 替换
% 全文
$ 最后一行
1 第一行
g global? 就是在前面指定的行中替换所有匹配的字符串,如果不加这个就只匹配每一行中的第一个,此处还可以用c p
c 每次替换前会确认

另外,有时候也会出现:g 这种命令,关于g和s的区别:

https://stackoverflow.com/questions/25684559/what-is-the-difference-between-g-and-s-commands-in-vim
总结一下,就是g是行选择器(所以d可以和g一起用:g/xxx/d,删除字符串出现的行),s相当于一个函数
所以可以有这写写法

:g/foo/s/bar/blah/g  

一般上面的命令中foo 和 bar 会是相同的,也就是

:g/foo/s/foo/blah/g

所以会有

:g//s/foo/blah/g

或者

:g/boo/s//blah/g

最后,换行符的匹配和替换

:%s/,/,\r/g #逗号处增加换行符
:%s/,\n/,/g #删除换行符

8.sudo 会重置环境变量,并且/etc/bashrc中export 的环境变量也会失效
原因:

sudo -l # env_reset
1
方法一:

visudo # env_reset -> !env_reset
# 或者直接改文件
vim /etc/sudoers #此文件root默认也没有写权限,所有不建议吧

方法二: 1

通过visudo命令,向sudoers文件中env_reset下增加一行:

Defaults env_keep="PATH PYTHONPATH LD_LIBRARY_PATH CAFFE_ROOT"

vim /etc/sudoers #此文件root默认也没有写权限,所有不建议吧

 

四.  Search and replace

Vim provides the :s (substitute) command for search and replace; this tip shows examples of how to substitute. On some systems, gvim has Find and Replace on the Edit menu (:help :promptrepl), however it is easier to use the :s command due to its command line history and ability to insert text (for example, the word under the cursor) into the search or replace fields.

Basic search and replaceedit | edit source

The :substitute command searches for a text pattern, and replaces it with a text string. There are many options, but these are what you probably want:

:s/foo/bar/g
Find each occurrence of 'foo' (in the current line only), and replace it with 'bar'.
:%s/foo/bar/g
Find each occurrence of 'foo' (in all lines), and replace it with 'bar'.
:%s/foo/bar/gc
Change each 'foo' to 'bar', but ask for confirmation first.
:%s/\<foo\>/bar/gc
Change only whole words exactly matching 'foo' to 'bar'; ask for confirmation.
:%s/foo/bar/gci
Change each 'foo' (case insensitive due to the i flag) to 'bar'; ask for confirmation.
:%s/foo\c/bar/gc is the same because \c makes the search case insensitive.
This may be wanted after using :set noignorecase to make searches case sensitive (the default).
:%s/foo/bar/gcI
Change each 'foo' (case sensitive due to the I flag) to 'bar'; ask for confirmation.
:%s/foo\C/bar/gc is the same because \C makes the search case sensitive.
This may be wanted after using :set ignorecase to make searches case insensitive.

The g flag means global – each occurrence in the line is changed, rather than just the first. This tip assumes the default setting for the 'gdefault' and 'edcompatible' option (off), which requires that the g flag be included in %s///g to perform a global substitute. Using :set gdefault creates confusion because then %s/// is global, whereas %s///g is not (that is, g reverses its meaning).

When using the c flag, you need to confirm for each match what to do. Vim will output something like: replace with foobar (y/n/a/q/l/^E/^Y)? (where foobar is the replacement part of the :s/.../.../ command. You can type y which means to substitute this match, n to skip this match, a to substitute this and all remaining matches ("all" remaining matches), q to quit the command, l to substitute this match and quit (think of "last"), ^E to scroll the screen up by holding the Ctrl key and pressing E and ^Y to scroll the screen down by holding the Ctrl key and pressing Y. However, the last two choices are only available, if your Vim is a normal, big or huge built or the insert_expand feature was enabled at compile time (look for +insert_expand in the output of :version).

Also when using the c flag, Vim will jump to the first match it finds starting from the top of the buffer and prompt you for confirmation to perform replacement on that match. Vim applies the IncSearch highlight group to the matched text to give you a visual cue as to which match it is operating on (set to reverse by default for all three term types as of Vim 7.3). Additionally, if more than one match is found and you have search highlighting enabled with :set hlsearch, Vim highlights the remaining matches with the Search highlight group. If you do use search highlighting, you should make sure that these two highlight groups are visually distinct or you won't be able to easily tell which match Vim is prompting you to substitute.

Detailsedit | edit source

Search range:

:s/foo/bar/g Change each 'foo' to 'bar' in the current line.
:%s/foo/bar/g Change each 'foo' to 'bar' in all the lines.
:5,12s/foo/bar/g Change each 'foo' to 'bar' for all lines from line 5 to line 12 (inclusive).
:'a,'bs/foo/bar/g Change each 'foo' to 'bar' for all lines from mark a to mark b inclusive (see Note below).
:'<,'>s/foo/bar/g When compiled with +visual, change each 'foo' to 'bar' for all lines within a visual selection. Vim automatically appends the visual selection range ('<,'>) for any ex command when you select an area and enter :. Also, see Note below.
:.,$s/foo/bar/g Change each 'foo' to 'bar' for all lines from the current line (.) to the last line ($) inclusive.
:.,+2s/foo/bar/g Change each 'foo' to 'bar' for the current line (.) and the two next lines (+2).
:g/^baz/s/foo/bar/g Change each 'foo' to 'bar' in each line starting with 'baz'.
Note: As of Vim 7.3, substitutions applied to a range defined by marks or a visual selection (which uses a special type of marks '< and '>) are not bounded by the column position of the marks by default. Instead, Vim applies the substitution to the entire line on which each mark appears unless the \%V atom is used in the pattern like: :'<,'>s/\%Vfoo/bar/g.


When searching:

.*\[^, and $ are metacharacters.
+?|&{(, and ) must be escaped to use their special function.
\/ is / (use backslash + forward slash to search for forward slash)
\t is tab, \s is whitespace (space or tab)
\n is newline, \r is CR (carriage return = Ctrl-M = ^M)
After an opening [, everything until the next closing ] specifies a /collection. Character ranges can be represented with a -; for example a letter a, b, c, or the number 1 can be matched with [1a-c]. Negate the collection with [^ instead of [; for example [^1a-c] matches any character except a, b, c, or 1.
\{#\} is used for repetition. /foo.\{2\} will match foo and the two following characters. The \ is not required on the closing } so /foo.\{2} will do the same thing.
\(foo\) makes a backreference to foo. Parenthesis without escapes are literally matched. Here the \ is required for the closing \).

When replacing:

\r is newline, \n is a null byte (0x00).
\& is ampersand (& is the text that matches the search pattern).
\0 inserts the text matched by the entire pattern
\1 inserts the text of the first backreference. \2 inserts the second backreference, and so on.

You can use other delimiters with substitute:

:s#http://www.example.com/index.html#http://example.com/#

Save typing by using \zs and \ze to set the start and end of a pattern. For example, instead of:

:s/Copyright 2007 All Rights Reserved/Copyright 2008 All Rights Reserved/

Use:

:s/Copyright \zs2007\ze All Rights Reserved/2008/

Using the current word or registersedit | edit source

 

:%s//bar/g
Replace each match of the last search pattern with 'bar'.
For example, you might first place the cursor on the word foo then press * to search for that word.
The above substitute would then change all words exactly matching 'foo' to 'bar'.
:%s/foo/<c-r><c-w>/g
Replace each occurrence of 'foo' with the word under the cursor.
<c-r><c-w> means that you press Ctrl-R then Ctrl-W.
The word under the cursor will be inserted as though you typed it.
:%s/foo/<c-r><c-a>/g
Replace each occurrence of 'foo' with the WORD under the cursor (delimited by whitespace).
<c-r><c-a> means that you press Ctrl-R then Ctrl-A.
The WORD under the cursor will be inserted as though you typed it.
:%s/foo/<c-r>a/g
Replace each occurrence of 'foo' with the contents of register 'a'.
<c-r>a means that you press Ctrl-R then a.
The contents of register 'a' will be inserted as though you typed it.
:%s/foo/<c-r>0/g
Same as above, using register 0 which contains the text from the most recent yank command. Examples of yank (copy) commands are yi( which copies the text inside parentheses around the cursor, and y$ which copies the text from the cursor to the end of the line. After a yank command which did not specify a destination register, the copied text can be entered by pressing Ctrl-R then 0.
:%s/foo/\=@a/g
Replace each occurrence of 'foo' with the contents of register 'a'.
\=@a is a reference to register 'a'.
The contents of register 'a' is not shown in the command. This is useful if the register contains many lines of text.
:%s//<c-r>//g
Replace each match of the last search pattern with the / register (the last search pattern).
After pressing Ctrl-R then / to insert the last search pattern (and before pressing Enter to perform the command), you could edit the text to make any required change.
:%s/<c-r>*/bar/g
Replace all occurrences of the text in the system clipboard (in the * register) with 'bar' (see next example if multiline).
On some systems, selecting text (in Vim or another application) is all that is required to place that text in the * register.
:%s/<c-r>a/bar/g
Replace all occurrences of the text in register 'a' with 'bar'.
<c-r>a means that you press Ctrl-R then a. The contents of register 'a' will be inserted as though you typed it.
Any newlines in register 'a' are inserted as ^M and are not found.
The search works if each ^M is manually replaced with '\n' (two characters: backslash, 'n').
This replacement can be performed while you type the command:
:%s/<c-r>=substitute(@a,"\n",'\\n','g')<CR>/bar/g
The "\n" (double quotes) represents the single character newline; the '\\n' (single quotes) represents two backslashes followed by 'n'.
The substitute() function is evaluated by the <c-r>= (Ctrl-R =) expression register; it replaces each newline with a single backslash followed by 'n'.
The <CR> indicates that you press Enter to finish the = expression.
:%s/<c-r>0/bar/g
Same as above, using register 0 which contains the text from the most recent yank command.

See Paste registers in search or colon commands instead of using the clipboard.

Additional examplesedit | edit source

:%s/foo/bar/
On each line, replace the first occurrence of "foo" with "bar".
:%s/.*\zsfoo/bar/
On each line, replace the last occurrence of "foo" with "bar".
:%s/\<foo\>//g
On each line, delete all occurrences of the whole word "foo".
:%s/\<foo\>.*//
On each line, delete the whole word "foo" and all following text (to end of line).
:%s/\<foo\>.\{5}//
On each line, delete the first occurrence of the whole word "foo" and the following five characters.
:%s/\<foo\>\zs.*//
On each line, delete all text following the whole word "foo" (to end of line).
:%s/.*\<foo\>//
On each line, delete the whole word "foo" and all preceding text (from beginning of line).
:%s/.*\ze\<foo\>//
On each line, delete all the text preceding the whole word "foo" (from beginning of line).
:%s/.*\(\<foo\>\).*/\1/
On each line, delete all the text preceding and following the whole word "foo".
:%s/\<foo\(bar\)\@!/toto/g
On each line, replace each occurrence of "foo" (which starts a word and is not followed by "bar") by "toto".
:s/^\(\w\)/\u\1/
If the first character at the beginning of the current line only is lowercase, switch it to uppercase using \u (see switching case of characters).
:%s/\(.*\n\)\{5\}/&\r/
Insert a blank line every 5 lines.
The pattern searches for \(.*\n\) (any line including its line ending) repeated five times (\{5\}).
The replacement is & (the text that was found), followed by \r (newline).
:%s/\<foo\(\a*\)\>/\=len(add(list, submatch(1)))?submatch(0):submatch(0)/g
Get a list of search results. (the list must exist)
Sets the modified flag, because of the replacement, but the content is unchanged.
Note: With a recent enough Vim (version 7.3.627 or higher), you can simplify this to:
:%s/\<foo\(\a*\)\>/\=add(list, submatch(1))/gn
This has the advantage, that the buffer won't be marked modified and no extra undo state is created. The expression in the replacement part is executed in the sandbox and not allowed to modify the buffer.

Special casesedit | edit source

For substituting patterns with corresponding case-sensitive text, Michael Geddes's keepcase plugin can be used, e.g.:

:%SubstituteCase/\cHello/goodBye/g
Substitute 'Hello hello helLo HELLO' by 'Goodbye goodbye goodBye GOODBYE'

For changing the offsets in a patch file (line number of a block), this little snippet can be used:

s/^@@ -\(\d\+\),\(\d\+\) +\(\d\+\),\(\d\+\) @@$/\="@@ -".eval(submatch(1)+offsetdiff).",".submatch(2)." +".eval(submatch(3)+offsetdiff).",".submatch(4)." @@"/g

Useful when we want to strip some blocks from a patch, without patch having to complain about offset differences.

Note Should try to make the expression more compact, but don't know how without having the possibility of modifying unwanted lines.

参考:

https://www.cnblogs.com/helloweworld/p/3525613.html

https://www.jianshu.com/p/3abd6fbc3322

https://blog.csdn.net/harryhare/article/details/80624648

https://vim.fandom.com/wiki/Search_and_replace

posted @ 2021-04-16 11:55  7bGWFm  阅读(276)  评论(0编辑  收藏  举报