Vim 实用技巧必知必会
吴咏炜
前 Intel 资深软件架构师
21753 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 25 讲
Vim 实用技巧必知必会
15
15
1.0x
00:00/00:00
登录|注册

07|正则表达式:实现文件内容的搜索和替换

2. 使用 Vim 替换命令完成函数名称转换任务
1. 搜索“/* */”注释的命令
建议查阅 Vim 的帮助文档
建议多练习掌握正则表达式搜索和替换
替换时引用前面匹配的内容
常用搜索命令 *
特殊含义字符和表达式
Vim 支持搜索和替换,使用正则表达式
替换实例
替换标志
特殊转义字符
计算替换结果
大小写转换
保留匹配中的字符
替换命令的复杂情况
取消搜索加亮
最长匹配和最短匹配
搜索实例
其他特殊字符:\<\>\s\S\d\D\x\X\w\W\h\H\c
特殊表达式:\?\+\{n,m}\(\)\&\|
特殊含义字符:.*^$~[]\
待查找内容被视为正则表达式
/:s 命令的基本用法
课后练习
内容小结
替换
搜索
Vim 的正则表达式

该思维导图由 AI 生成,仅供参考

你好,我是吴咏炜。
上面两讲里我们讨论了如何找到你想要查看 / 编辑的文件,及如何处理多个文件。今天我们来看一下如何在一个文件中搜索和替换内容,其核心主题就是正则表达式。

正则表达式搜索

通过 Vim 教程,你已经学到了搜索命令 / 和替换命令 :s 的基本用法。教程里没有提到的是,你输入的待查找的内容是被 Vim 当成正则表达式来看待的。正则表达式的学习资料很多(极客时间上就有专门的课程),完整学习也相当复杂,我们就不从头学习了。下面我们会简单讨论的,是 Vim 里的正则表达式,重点是它和其他常用正则表达式(正则表达式还是有很多种不同的风格的)的区别之处。如果你之前对正则表达式完全没有了解,建议你这儿暂停一下,先在网上搜索一下关于正则表达式的资料,了解它的基本概念和用法,然后继续阅读。
在一个搜索表达式里,或者称为模式(pattern;注意不要和 Vim 的 mode 混淆)里,.*^$~[]\ 是有特殊含义的字符:
. 可以匹配除换行符外的任何字符:如 a. 可以匹配“aa”、“ab”、“ac”等,但不能匹配“a”、“b”或“ba”。如果需要匹配换行符(跨行匹配)的话,则需要使用 \_.
* 表示之前的匹配原(最普通的情况为单个字符)重复零次或多次:如 aa* 可以匹配“a”、“aa”或“aaa”,a.* 可以匹配“a”、“aa”、“abc”等等,但两者均不能匹配“b”。
^ 匹配一行的开头,如果出现在模式的开头的话;在其他位置代表字符本身。
$ 匹配一行的结尾,如果出现在模式的结尾的话;在其他位置代表字符本身。
~ 匹配上一次替换的字符串,即如果上一次你把“foo”替换成了“bar”,那 ~ 就匹配“bar”。
[…] 匹配方括号内的任一字符;方括号内如果第一个字符是 ^,表示对结果取反;除开头之外的 - 表示范围:如 [A-Za-z] 表示任意一个拉丁字母,[^-+*/] 表示除了“+”、“-”、“*”、“/”外的任意字符。
\ 的含义取决于下一个字符,在大部分的情况下,包括上面的这几个(.*\^$~[]),代表后面这个字符本身;在跟某些字符时则有特殊含义(后面我们会讨论最重要的那些)。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

Vim 正则表达式搜索和替换技巧 Vim 中的正则表达式在文件内容的搜索和替换中发挥着重要作用。本文详细介绍了在 Vim 中使用正则表达式进行搜索和替换的基本方法和特点。通过 `/` 和 `:s` 命令,读者可以学习如何利用正则表达式进行文件内容的查找和替换。文章深入讲解了搜索模式中的特殊字符和其含义,以及如何使用特殊模式项进行高效的匹配。此外,还分享了一些实际的搜索实例,帮助读者更好地理解正则表达式的应用。 在替换部分,文章介绍了一些复杂的替换情况,包括保留匹配中的某些字符、大小写转换、计算替换结果等。还详细讲解了在替换字符串中引用前面匹配内容的方法,以及 Vim 中的特殊替换字符串和标志的使用。通过实例演示,读者可以更好地掌握 Vim 中正则表达式替换的技巧。 总的来说,本文内容密集,但重点突出。读者可以通过本文快速了解 Vim 中正则表达式的基本知识,提高文件内容处理的效率。文章内容丰富,建议读者多加练习,以便更好地掌握正则表达式搜索和替换的技巧。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Vim 实用技巧必知必会》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(16)

  • 最新
  • 精选
  • 我来也
    课后练习: # 1. 如果要搜索“/* */”注释的话 参考文中的替换正则表达式(第一个`:`是命令行模式的前缀,执行时不需要贴入.) ``` :%s!/\*\_.\{-}\*/!!g ``` 稍作修改即可(第一个`/`是查找命令的前缀,搜索时不需要贴入.) ``` /\/\*\_.\{-}\*\/ ``` # 2. 把 begin_search_nocase 这样的函数名称转变成 BeginSearchNocase 可以分两步走: 1. 使用文中的命令,将首字母替换成大写 ``` %s/\<\(_*\)\([a-z]\w*\)\ze(/\1\u\2/g ``` 2. 将函数名中`_`后面的字符替换成大写: ``` %s/\<_*[A-Z]\zs\(\w*\)\ze(/\=substitute(submatch(1),'_\+\(\w\)','\=toupper(submatch(1))','g')/g ``` 测试用例 替换前: ``` begin_search_nocase() beGin_seaRch_noCase() _beGin_seaRch_nocase_100_() ``` 替换后: ``` BeginSearchNocase() BeGinSeaRchNoCase() _BeGinSeaRchNocase100_() ``` 3. 两步合一步的搞法:(不太推荐) ``` %s/\<_*\zs\([a-zA-Z]\w*\)\ze(/\=substitute(substitute(submatch(1),'^','_',''),'_\+\(\w\)','\=toupper(submatch(1))', 'g')/g ``` a. 使用`\zs\([a-zA-Z]\w*\)\ze(`找到函数名的边界 b. 将提取出来的名称添加前缀`_`,方便后面的替换.`substitute(submatch(1),'^','_','')` c. 将名称中`_`后面的字符替换成大写.`substitute('步骤b返回的结果','_\+\(\w\)','\=toupper(submatch(1))', 'g')` 4. 测试用例单词中间的大写字母并没变,按理说是需要变成小写的. 这个正则可以做到: ``` %s/\<_*\zs\([a-zA-Z]\w*\)\ze(/\=substitute(substitute(submatch(1),'\C\(_\)\=\(.\)','\=submatch(1)==""?tolower(submatch(2)) : toupper(submatch(2))', 'g'),'^.','\u&', 'g')/g ``` 实现的效果是: ``` BeginSearchNocase() BeginSearchNocase() _BeginSearchNocase100_() ``` # 开心的带货环节 强烈推荐一个vim中多光标的插件 [vim-visual-multi](https://github.com/mg979/vim-visual-multi) 我以前都是用`.`命令,或者宏来实现类似的效果,但是并不直观和方便. 第四个正则并不是我想到的,我只是把插件[vim-visual-multi](https://github.com/mg979/vim-visual-multi/blob/cb994375fcbf032adfef6d31d8fcfa59bab381c8/autoload/vm/special/case.vim#L22-L34) 中的代码拿来改了一下. 这个插件可以在vim中实现多光标编辑,实现Sublime中的那种效果. 我觉得比Sublime中的多行编辑还厉害多了. 就连7.5k stars的[vim-multiple-cursors](https://github.com/terryma/vim-multiple-cursors)都推荐使用`vim-visual-multi`. 可惜谷歌上都无法搜索到该插件的中文介绍. -- 如果是课后练习2中的需求,使用该插件,就非常非常简单了. 1. 在搜索命令中查找要匹配的函数名:(第一个`/`不需要贴入) ``` /\<_*\zs[a-zA-Z]\w*\ze( ``` 2. 在普通模式中全选文件内容 `ggVG` 3. 用插件的多光标来选中上次搜索的内容`<leader><leader>f` 4. 唤出插件的字符转换功能`<leader><leader>C` [:help vm-case-conversion] 有很多种转换规则,下划线转驼峰只是其中的一个功能. 5. 使用其中的`P`选项即可实现效果.

    作者回复: 就属你最牛了。这回我都了解了些新东西。😝

    2020-08-07
    13
  • 我来也
    # 又是一篇非常全面的课程. 如果是0基础的人看了,估计就要入门到放弃了.哈哈. 正则本身就有点小复杂,再加上vi中有些模式跟主流的还不太一样. # 今天学到的新知识: 在正则中,我之前虽然也知道vim有贪婪模式和最短匹配,但是真没细究过. 今天看了老师的`<.\{-1,}>`和`:%s!/\*\_.\{-}\*/!!g`,才知道这东西写起来也不复杂. 具体的可以查看帮助: `:help /multi` \{-} \{-} 0 或更多 尽可能少 # 我介绍下搜索中,我非常常用的特殊模式项: `\c` : 强制忽略大小消息 `\C` : 强制开启大消息匹配 (`\v`和`\V`用的不多,但知道是怎么回事.) 另外,我一般会开启搜索相关的两个选项: set ignorecase " Case insensitive search set smartcase " Case sensitive when uc present 忽略大消息 和 智能大小写. 在查询的内容中有大写字母时,就区分大小写,否则就是不区分. 在确定只需要查询小写字母时,需要在搜索模式中加上`\c`. # 补充下普通模式下的全字匹配光标所在的关键字 向后搜索 `*` : 是全字匹配,会在搜索关键字前后自动添加`\<`和`\>` `g*`: 不开启全字匹配,不自动添加`\<`和`\>` 对应的还有 向前搜索 `#` : 全字匹配 `g#`: 不开启全字匹配 vim中的命令繁多,还是配套起来记记得更牢. # 对于取消搜索高亮,我也有这种需求. 我也是映射了快捷键,但只映射了普通模式的,没有映射插入模式的. 我的方式是在普通模式下,按删除键时,附带的取消高亮. nnoremap <silent> <BS> <BS>:nohlsearch<CR> 我也见过用如下按键映射的: nnoremap <silent> <leader>/ :nohlsearch<CR> 由于我的键盘上不方便按F1-12,所以可选择的映射键并不多.

    作者回复: 很好的经验分享。👍

    2020-08-07
    7
  • Ranger
    :%s/\<\(_*\)\([a-z]\w*\)\ze(/\1\u\2/g 你好,想问一下,\<\(_*\) , 这里的 _ 是换行符的意思吗?

    作者回复: 不是,就是处理标识符以“_”开始的情况。

    2020-08-14
    2
  • Adoy
    感谢老师用心分享,里面的知识都十分实用!有一个平板的小建议,正则表达式的命令能否用行内代码(markdown里应该是'`' 和 '`' ),看得眼花缭乱哈哈哈

    作者回复: 已经用了。极客时间的展示没有背景加灰,有时候不够明显。

    2020-08-07
    1
  • 阿鸡
    2. %s!\(\<\|_\)\([a-z]\)!\U\2!g

    作者回复: 👍

    2022-04-15
  • Alvin-L
    :%s/\<\(_*\)\([a-z]\w*\)\ze(/\1\u\2/g [ 关键是要理解中间这段的意思(从:%s/之后,一直到末尾/g之前), 由于命令没有使用!,所以这条替换命令/是作为功能符使用,/前为模式串,/后是替换串 1,模式串 \<\(_*\)\([a-z]\w*\)\ze( , 2,替换串 \1\u\2 模式串再分成了四段 \< , \(_*\) , \([a-z]\w*\) , /ze( \< 表示一个单词的开头 \(_*\): 分3节,最开头的 \( 与末尾的 \) 表示捕获包起来的内容作为一个分组,并将分组分配为1号,而中间包起来的 _* 表示重复出现任意次(0次1次多次)的下划线_ \([a-z]\w*\) 也分3节, \( 与 \) 捕获分组2号.中间的[a-z]\w* 表示一个小写字母后跟着可重复出现任意次的单词 /ze( 表示模式串匹配的结尾必须紧跟着'('但不包括'(' 替换部分分成两段\1 , \u\2 \1 表示在模式串匹配中捕捉到的1号分组的内容(即0个或多个下划线_) \u\2 表示在模式串匹配中捕捉到的2号分组的内容(即1个小写字符跟着0个或多个标识符),将其第一个字符(即匹配里值得的那个小写字符)变为大写 所以整个意思就是: 匹配到以下划线_开始(或者没有下划线_)第一个字符是小写字符后面跟着任意长度的标识符的字符串(且该字符串紧跟着左圆括号,但不包括左圆括号).然后将第一个小写字符变为大写字符 ]

    作者回复: 学习很努力啊。理解正确。 新年快乐!

    2021-02-14
  • pearl刘东洋
    两个疑问 1、不过,这样的写法会让像 > 这样的结尾字符在模式中重复出现,因此这并不是最理想的写法——这句没太理解,有同学帮忙举例子解释一下吗? 2、\H 匹配非单词首字符,相当于 ^[A-Za-z_] 这句应该是 \H 匹配非单词首字符,相当于 [^A-Za-z_] 吧

    作者回复: 1. 就是指“<[^>]\+>”里把“>”重复了的情况。 2. 嗯嗯,是打字错误。我回头更正一下。谢谢。

    2021-01-08
  • pyhhou
    替换那边不是很理解,之前一直以为替换是像下面的格式,匹配的内容和替换的内容中间用空格分开 :%s matchpattern replacepattern 上面 3 个替换的例子,我尝试理解: :%s!\s*//.*$!! ! 可以代替 \, 是不是表示的就是替换后的内容,这里可以理解为直接删除。后面的 \s*//.*$!! 表示的是需要在文本中搜索的内容 :%s!/\*\_.\{-}\*/!!g 按上面的理解方式,第二个例子也是类似的,只不过需要搜索的内容是 /\*\_.\{-}\*/!!,另外最后的 g 表示一行内允许多次搜索 :%s/\<\(_*\)\([a-z]\w*\)\ze(/\1\u\2/g 到这里就不是太理解了,\<\(_*\)\([a-z]\w*\)\ze( 表示的是需要搜索匹配的内容,后面才是需要替换的内容? 感觉主要是 ! 和 / 还有 \ 这三个东西放在一起,看得是真的有点混淆它们具体的意义。还请老师解答一下替换的结构

    作者回复: :s 后面的符号是替换的间隔符,但有一定的限制范围。见 :help pattern-delimiter。“:s/搜索/替换/标志”、“:s!搜索!替换!标志”、“:s#搜索#替换#标志”等等都可以的。 对,最后一个替换命令里,\<\(_*\)\([a-z]\w*\)\ze( 是搜索模式,\1\u\2 是替换模式。

    2020-08-21
  • __@948CSheLL
    老师您好,我想请问一下【:%s】和【:s】有什么区别?

    作者回复: % 代表所有行。也可以用“起始行号,结束行号"的写法。不写,就只替换当前行了。

    2020-08-17
  • Rock
    正则表达式有没有什么简单入门的教程

    作者回复: 我也和你一样,靠搜索查有哪些教程。先自己看看吧,有没有适合自己的。没免费的好教程的话,可以考虑极客时间的,哈哈。还有,就是直接看文中的例子,通过例子去理解。

    2020-08-11
收起评论
显示
设置
留言
16
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部