Wiki LogoWiki - The Power of Many

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-15

3.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  →  8

4. 全局命令 :g

:g 是 Vim 中最接近"元编程"的指令.

4.1 基本语法

:g/{pattern}/{command}      " 对匹配行执行命令
:v/{pattern}/{command}      " 对不匹配行执行命令 (反向)
:g!/{pattern}/{command}     " 同 :v

4.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 为什么用它?

  1. 全功能编辑: 你可以使用所有的 Vim 快捷键 (dw, cw, p 等) 来修改之前的长命令.
  2. 搜索历史: 可以搜索过往复杂的全局替换命令, 修改后按 <CR> 立即执行.
  3. 多行编辑: 虽然最终执行的是一行, 但你可以在这里构思复杂的逻辑.

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 正则搜索

  1. 搜索项目中所有 TODO 和 FIXME 注释
  2. 搜索所有函数定义
  3. 搜索格式不规范的代码 (如多余空格)

7.2 替换练习

  1. 将日期格式从 MM/DD/YYYY 转换为 YYYY-MM-DD
  2. var 替换为 const (仅在声明语句中)
  3. 使用 \= 生成递增 ID

7.3 全局命令

  1. 使用 :g/^$/d 删除空行
  2. 使用 :v/ERROR/d 提取错误日志
  3. 使用 :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. 思考题

  1. \v Very Magic 模式有什么优势?
  2. :g:s 有什么区别?
  3. 如何只计数匹配项而不替换?
  4. gn 动作有什么特殊之处?
  5. 如何在替换中使用 Vim 表达式?

搜索和替换是文本处理的核心能力. 掌握正则表达式和全局命令, 你将拥有批量处理的超能力.

On this page