W05: 搜索逻辑与全局处理
掌握 Very Magic 正则表达式, 深度解析全局指令 :g 的元编程能力与批量替换技巧.
1. 搜索基础
1.1 基本搜索
/{pattern} " 向前搜索
?{pattern} " 向后搜索
n " 下一个匹配
N " 上一个匹配
* " 搜索光标下的单词 (向前)
# " 搜索光标下的单词 (向后)
gd " 跳转到局部变量定义
gD " 跳转到全局变量定义1.2 搜索选项
:set hlsearch " 高亮匹配
:set incsearch " 增量搜索 (边输入边匹配)
:set ignorecase " 忽略大小写
:set smartcase " 智能大小写 (有大写则区分)
:noh " 取消高亮 (临时)1.3 搜索历史
q/ " 打开搜索历史窗口
Ctrl+p / Ctrl+n " 在搜索模式中浏览历史2. 正则表达式
2.1 Vim 正则模式
Vim 默认使用 "magic" 模式, 需要大量转义:
" 默认 magic 模式 - 需要转义
/\(foo\|bar\) " 匹配 foo 或 bar
/\d\+ " 匹配一个或多个数字2.2 Very Magic 模式 (\v)
推荐始终使用 \v 开启 Very Magic 模式:
" Very Magic - 类似 Perl/PCRE
/\v(foo|bar) " 匹配 foo 或 bar
/\v\d+ " 匹配一个或多个数字
/\v<\w+> " 匹配完整单词2.3 常用正则语法
" 在 \v 模式下
. " 任意字符
* " 0 次或多次
+ " 1 次或多次
? " 0 次或 1 次
{n,m} " n 到 m 次
\d " 数字 [0-9]
\w " 单词字符 [a-zA-Z0-9_]
\s " 空白字符
^ " 行首
$ " 行尾
< " 词首边界
> " 词尾边界
(...) " 分组
| " 或2.4 搜索实例
" 搜索函数定义 (Go)
/\vfunc\s+\w+\(
" 搜索 IP 地址
/\v\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}
" 搜索邮箱
/\v\w+\@\w+\.\w+
" 搜索 TODO 注释
/\v(TODO|FIXME|XXX):?
" 搜索非 ASCII 字符
/\v[^\x00-\x7F]3. 替换命令 (Substitute)
3.1 基本语法
:[range]s/{pattern}/{replacement}/[flags]3.2 范围
:s/old/new/ " 当前行第一个
:s/old/new/g " 当前行所有
:%s/old/new/g " 全文件
:5,10s/old/new/g " 第 5-10 行
:'<,'>s/old/new/g " 可视选区
:.,$s/old/new/g " 当前行到文件末尾3.3 常用标志
| 标志 | 含义 |
|---|---|
g | 全局 (行内所有匹配) |
c | 确认每次替换 |
i | 忽略大小写 |
I | 区分大小写 |
e | 忽略错误 (无匹配不报错) |
n | 只计数不替换 |
3.4 捕获组
" 交换赋值语句两边
:%s/\v(\w+) = (\w+)/\2 = \1/g
" a = b → b = a
" 添加引号
:%s/\v(\w+)/"\1"/g
" hello → "hello"
" 日期格式转换 MM/DD/YYYY → YYYY-MM-DD
:%s/\v(\d{2})\/(\d{2})\/(\d{4})/\3-\1-\2/g
" 01/15/2024 → 2024-01-153.5 特殊替换
" 使用匹配的整个内容
:%s/\v<\w+>/【&】/g
" hello → 【hello】
" 转大写/小写
:%s/\v(\w+)/\U\1/g " 转大写
:%s/\v(\w+)/\L\1/g " 转小写
:%s/\v(\w)/\u\1/g " 首字母大写3.6 表达式替换 (\=)
" 替换为行号
:%s/ID/\=line('.')/g
" 替换为递增数字
let g:n = 0 | %s/ITEM/\=printf("Item_%d", g:n + 1) | let g:n += 1/g
" 替换为计算结果
:%s/\v(\d+)\+(\d+)/\=submatch(1)+submatch(2)/g
" 5+3 → 84. 全局命令 :g
:g 是 Vim 中最接近"元编程"的指令.
4.1 基本语法
:g/{pattern}/{command} " 对匹配行执行命令
:v/{pattern}/{command} " 对不匹配行执行命令 (反向)
:g!/{pattern}/{command} " 同 :v4.2 常用示例
" 删除空行
:g/^$/d
" 删除注释行
:g/^\s*#/d
:g/^\s*\/\//d
" 保留匹配行 (删除其他)
:v/ERROR/d
" 在匹配行下方添加内容
:g/interface/norm o// TODO: implement
" 复制匹配行到文件末尾
:g/TODO/t$
" 移动匹配行到文件开头
:g/import/m0
" 对匹配行执行替换
:g/DEBUG/s/foo/bar/g
" 将匹配行追加到寄存器
qaq " 清空寄存器 a
:g/^function/y A " 追加到寄存器 a
"ap " 粘贴4.3 高级用法
" 删除重复行 (保留第一个)
:g/^\(.*\)$\n\1$/d
" 反转文件行顺序
:g/^/m0
" 打印匹配行 (不修改)
:g/ERROR/p
" 对匹配行计数
:g/TODO/echo line('.')
" 执行多个命令
:g/pattern/s/foo/bar/ | s/baz/qux/5. 命令行模式之王 (Command-line Window)
当你需要编写复杂的替换命令或正则表达式时, 在那行窄窄的命令行里编辑是非常痛苦的. Vim 提供了一个完整的 Buffer 来编辑命令.
5.1 进入命令窗口
q: " 打开命令历史窗口 (像编辑普通文本一样编辑命令)
q/ " 打开搜索历史窗口5.2 为什么用它?
- 全功能编辑: 你可以使用所有的 Vim 快捷键 (
dw,cw,p等) 来修改之前的长命令. - 搜索历史: 可以搜索过往复杂的全局替换命令, 修改后按
<CR>立即执行. - 多行编辑: 虽然最终执行的是一行, 但你可以在这里构思复杂的逻辑.
5.3 命令模式下的常用快捷键
在普通的命令行 (:) 下:
Ctrl + f " 从命令行切换到命令窗口 (q:)
Ctrl + r Ctrl + w " 插入光标下的单词
Ctrl + r {reg} " 插入寄存器内容6. 搜索与操作结合
6.1 gn 动作
gn 是一个特殊的 motion, 选中下一个搜索匹配:
/pattern " 搜索
cgn " 修改匹配项
. " 重复修改下一个这是批量修改的利器!
6.2 搜索 + 宏
/pattern " 搜索
qa " 开始录制
n " 找下一个
... " 操作
q " 停止录制
10@a " 执行 10 次7. 本周实战任务
7.1 正则搜索
- 搜索项目中所有 TODO 和 FIXME 注释
- 搜索所有函数定义
- 搜索格式不规范的代码 (如多余空格)
7.2 替换练习
- 将日期格式从
MM/DD/YYYY转换为YYYY-MM-DD - 将
var替换为const(仅在声明语句中) - 使用
\=生成递增 ID
7.3 全局命令
- 使用
:g/^$/d删除空行 - 使用
:v/ERROR/d提取错误日志 - 使用
:g/func/norm o// TODO批量添加注释
8. 配置建议
-- init.lua
-- 搜索配置
vim.opt.hlsearch = true -- 高亮搜索
vim.opt.incsearch = true -- 增量搜索
vim.opt.ignorecase = true -- 忽略大小写
vim.opt.smartcase = true -- 智能大小写
-- 取消搜索高亮
vim.keymap.set("n", "<Esc>", ":noh<CR>", { silent = true })
-- 始终保持搜索结果居中
vim.keymap.set("n", "n", "nzzzv")
vim.keymap.set("n", "N", "Nzzzv")
-- 快速替换光标下的单词
vim.keymap.set("n", "<leader>sr", ":%s/\\<<C-r><C-w>\\>/<C-r><C-w>/gI<Left><Left><Left>")9. 思考题
\vVery Magic 模式有什么优势?:g和:s有什么区别?- 如何只计数匹配项而不替换?
gn动作有什么特殊之处?- 如何在替换中使用 Vim 表达式?
搜索和替换是文本处理的核心能力. 掌握正则表达式和全局命令, 你将拥有批量处理的超能力.