强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

Vim / Neovim 完全指南 / 08 - 搜索与替换

“Know your regex, know your editor.”

8.1 搜索基础

8.1.1 基本搜索

/pattern        " 向前搜索
?pattern        " 向后搜索
n               " 下一个匹配
N               " 上一个匹配
*               " 搜索单词(光标下,向前)
#               " 搜索单词(光标下,向后)
g*              " 部分匹配(向前)
g#              " 部分匹配(向后)

8.1.2 搜索选项

/pattern/e      " 光标停在匹配末尾
/pattern/b      " 光标停在匹配开头
/pattern/+2     " 停在匹配下方 2 行
/pattern/-1     " 停在匹配上方 1 行

8.1.3 搜索设置

:set ignorecase     " 忽略大小写(ic)
:set smartcase      " 智能大小写(scs)— 有大写字母时区分
:set hlsearch       " 高亮搜索结果(hls)
:set incsearch      " 增量搜索(is)
:nohlsearch         " 取消高亮
:noh                " 同上
-- Neovim 配置
vim.opt.ignorecase = true
vim.opt.smartcase = true
vim.opt.hlsearch = true
vim.opt.incsearch = true

8.2 正则表达式(Regular Expression)

8.2.1 Vim 正则引擎

Vim 有 4 种正则模式:

前缀 名称 说明
magic 默认模式
\v very magic 接近标准正则语法
\m magic 等同默认
\M nomagic 特殊字符需转义
\V very nomagic 几乎所有字符按字面匹配
" 使用 \v(very magic)避免大量转义
/\vfunction\s+\w+        " 标准正则风格
/function\s\+\w\+        " 默认 magic 模式(需要转义 +)

" 使用 \V(very nomagic)搜索特殊字符
/\V$100.00               " 精确搜索 $100.00
/$100\.00                " 默认模式需要转义

8.2.2 常用正则模式

模式 含义 示例
. 任意字符 /a.c 匹配 abc, aXc
* 0 次或多次 /ab*c 匹配 ac, abc, abbc
\+ 1 次或多次 /ab\+c 匹配 abc, abbc
\? 0 次或 1 次 /ab\?c 匹配 ac, abc
\{n,m} n 到 m 次 /a\{2,4} 匹配 aa, aaa, aaaa
^ 行首 /^function 匹配行首的 function
$ 行尾 /end$ 匹配行尾的 end
\< 词首 \<word 匹配词首的 word
\> 词尾 word\> 匹配词尾的 word
\b 词边界 \bword\b 匹配完整单词
[] 字符类 /[aeiou] 匹配元音
[^] 否定字符类 /[^0-9] 匹配非数字
| /foo|bar 匹配 foo 或 bar
\(\) 分组 /\(foo\)\+ 匹配 foo, foofoo
\1 反向引用 /\(.\)\1 匹配连续相同字符

8.2.3 字符类(Character Class)

模式 含义
\d 数字 [0-9]
\D 非数字
\w 单词字符 [a-zA-Z0-9_]
\W 非单词字符
\s 空白字符
\S 非空白字符
\l 小写字母 [a-z]
\u 大写字母 [A-Z]
\a 字母 [a-zA-Z]
\h 字母或下划线

8.2.4 实用正则示例

" 匹配邮箱
/\v[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}

" 匹配 IP 地址
/\v\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}

" 匹配 URL
/\vhttps?://[^\s]+

" 匹配 HTML 标签
/\v\<\zs[^>]+\ze\>

" 匹配函数定义(Python)
/\v^\s*(def|class)\s+\w+

" 匹配中文字符
/\v[\x{4e00}-\x{9fff}]

8.3 替换(Substitute)

8.3.1 替换语法

:[range]s/pattern/replacement/[flags]
参数 说明
range 范围(% 全文, 1,10 第1-10行, '<,'> 选区)
pattern 搜索模式
replacement 替换文本
flags 标志(g 全局, c 确认, i 忽略大小写, e 无错)

8.3.2 替换标志

标志 含义
g 全局替换(一行中所有匹配)
c 逐个确认(confirm)
i 忽略大小写
I 区分大小写
e 不显示错误
n 只计数不替换
& 复用上次标志

8.3.3 替换范围

:s/old/new/g           " 当前行全局替换
:%s/old/new/g          " 全文替换
:1,10s/old/new/g       " 第 1-10 行替换
:'<,'>s/old/new/g      " 可视选区替换
:'<,'>s/old/new/gc     " 选区替换(逐个确认)
:.,$s/old/new/g        " 当前行到文件末尾
:.,+5s/old/new/g       " 当前行及以下 5 行

8.3.4 替换中的特殊字符

字符 含义
\r 换行
\n NULL 字节(替换中用 \r 表示换行)
\t Tab
\\ 反斜杠
\0 整个匹配
\1-\9 第 N 个捕获组
\u 下一个字符大写
\U 后续字符大写
\l 下一个字符小写
\L 后续字符小写
\e 结束 \U 或 \L
&\0 整个匹配

8.3.5 替换实战

" 基本替换
:%s/foo/bar/g              " 全文 foo → bar
:%s/foo/bar/gc             " 逐个确认

" 大小写转换
:%s/\v(\w+)/\U\1/g         " 全文转大写
:%s/\v^(\w)/\u\1/g         " 每行首字母大写

" 行操作
:%s/\v^$/\r/               " 空行后加一行
:%s/\v^\s+$//g             " 删除只含空白的行
:%s/\v\n\n+/\r\r/g         " 多个空行压缩为一个

" 添加行号
:%s/^/\=line('.').'. '/    " 每行前添加行号

" 删除行
:%g/^\s*$/d                " 删除空行
:%v/pattern/d              " 删除不包含 pattern 的行

" 交换捕获组
:%s/\v(\w+)\s+(\w+)/\2 \1/g   " 交换两个单词

" 引号转换
:%s/"/'/g                  " 双引号转单引号

" 日期格式转换
:%s/\v(\d{4})-(\d{2})-(\d{2})/\3\/\2\/\1/g  " 2024-01-15 → 15/01/2024

8.3.6 替换表达式

" 在替换中使用表达式
:%s/\v\d+/\=submatch(0)*2/g        " 所有数字乘以 2
:%s/\v\d+/\=printf('%04d', submatch(0))/g  " 数字补零到 4 位

8.4 全局命令(Global)

8.4.1 基本语法

:[range]g/pattern/command

对匹配 pattern 的行执行 command

8.4.2 常用全局命令

" 列出匹配的行
:g/pattern/p

" 删除匹配的行
:g/pattern/d

" 删除不匹配的行
:v/pattern/d        " 等同 :g!/pattern/d

" 复制匹配的行到文件末尾
:g/pattern/t$

" 移动匹配的行到文件末尾
:g/pattern/m$

" 对匹配行执行 Normal 模式命令
:g/pattern/normal @q    " 对匹配行执行宏 q

" 在匹配行上方添加文本
:g/pattern/-1append\nNew line here

" 给匹配行添加行号
:g/pattern/s/^/\=line('.').': '/

8.4.3 全局命令实战

" 删除所有注释行(Python)
:v/^\s*#/d              " 保留注释行,删除其余
:g/^\s*#/d              " 删除注释行

" 删除所有 debug 语句
:g/console\.\(log\|debug\)/d

" 将所有 TODO 行复制到文件末尾
:g/TODO/t$

" 给所有函数添加注释
:g/^def /normal O# TODO: implement this

8.5 vimgrep 与 Grep

8.5.1 内置 vimgrep

:vimgrep pattern files     " 搜索文件
:vimgrep /TODO/ **/*.py    " 搜索所有 Python 文件中的 TODO
:vim /function/ src/**/*.js  " 搜索 JavaScript 文件
" 导航结果
:copen        " 打开 quickfix 窗口
:cclose       " 关闭 quickfix
:cn           " 下一个匹配
:cp           " 上一个匹配
:cfirst       " 第一个匹配
:clast        " 最后一个匹配

8.5.2 外部 grep

:grep pattern files          " 使用外部 grep
:grep! -r "TODO" .           " 递归搜索
:copen                        " 查看结果

8.5.3 ripgrep 集成

-- 使用 ripgrep 作为 grep 程序
vim.opt.grepprg = "rg --vimgrep --no-heading --smart-case"
vim.opt.grepformat = "%f:%l:%c:%m"

8.6 搜索高亮管理

:noh                " 临时取消高亮
:set nohlsearch     " 永久取消高亮
" 或使用映射
nnoremap <Esc> :noh<CR><Esc>

8.7 业务场景

场景 方法
全局重命名变量 :%s/old_name/new_name/g
删除空行 :g/^\s*$/d
提取 TODO :g/TODO/p 或 vimgrep
批量注释 :'<,'>s/^/#/g
代码审查 vimgrep + quickfix
格式化日期 :%s + 捕获组
去重排序 :sort u

8.8 总结

功能 命令
搜索 /pattern ?pattern * # n N
替换 :[range]s/pattern/repl/[flags]
全局命令 :[range]g/pattern/command
文件搜索 :vimgrep :grep
结果导航 :copen :cn :cp :cc

下一步第 09 章 - VimScript 编程 → 学习 Vim 的脚本语言,编写函数和自动命令。


扩展阅读