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

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默认模式
\vvery magic接近标准正则语法
\mmagic等同默认
\Mnomagic特殊字符需转义
\Vvery 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换行
\nNULL 字节(替换中用 \r 表示换行)
\tTab
\\反斜杠
\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 的脚本语言,编写函数和自动命令。


扩展阅读