vim无法单靠正则自动去重,需结合:sort u、:global+正则、宏或awk等实现按内容去重、保序、忽略空行/注释等功能。

在 Vim 中直接用正则无法“自动去重”重复行,因为正则本身不带状态记忆和跨行比较能力;但结合 Vim 内置命令(:global、:sort、:uniq)与高级正则匹配逻辑,可高效完成**按内容去重、保留首次出现、忽略空行/注释等干扰项**的操作。
用 :sort u 快速去重(最简方案)
这是 Vim 原生命令中最常用、最可靠的方式,底层基于排序后合并相邻相同行:
-
:sort u—— 对全文排序并去重,会改变原始顺序 -
:g/^$/d—— 先删空行(避免空行被当作唯一行保留) -
:sort u后若需恢复原序,不可逆;如必须保序,需用更精准方法
保序去重:用 :global + 正则标记 + 删除后续重复
核心思路:从上到下遍历,对每一行,删除其下方所有完全相同的行。需配合 Vim 的 (very magic)模式简化正则书写:
- 先清除空行和纯注释行(可选):
:g/^s*(//|#|/*|$)/d - 执行保序去重:
:g/./if search('^'.escape(getline('.'), '.^$*').'$','Wn') | .+1,$g/^'.escape(getline('.'), '.^$*').'$/d | endif - 说明:对每一非空行,用
search()查找它在当前行之后是否再次出现;若找到,则用:g删除所有后续匹配行 - ⚠️ 注意:
escape()防止行中含正则元字符(如.、$、^)导致误匹配
用宏 + 正则实现交互式可控去重
适合小范围、需人工确认的场景(例如只去重某段配置或日志):
-
qa开始录制宏 a -
Y/V<c-r>"<cr></cr></c-r>—— 复制当前行,粘贴为字面量搜索(V关闭正则元字符) -
j下移一行,:g/^".*$//d—— 删除下方所有完全相同的行(注意此处用"寄存器内容需提前转义,实际推荐改用/V<c-r>0<cr></cr></c-r>) -
q结束录制,@a执行,@@重复 - 更稳妥做法:用
:let @a = "y$/\V<c-r>0<cr>j:g/^".@0."$/d<cr>"</cr></cr></c-r>直接定义宏(需在命令行中输入,<c-r>0</c-r>表示寄存器 0 内容)
结合外部工具(awk/sort)实现语义级去重
当需忽略首尾空格、忽略大小写、或按某列去重时,Vim 内置命令力有不逮,可调用 shell:
- 选中要处理的行(
V可视行模式),然后:!awk '!seen[tolower($0)]++'—— 小写不敏感去重,保序 - 按前两列去重:
!awk '!seen[$1,$2]++' - 忽略首尾空白后去重:
!awk '{$1=$1}; !seen[$0]++'($1=$1强制重格式化,压缩空白) - 优点:表达力强、逻辑清晰;缺点:依赖外部命令,不适用于无 shell 环境











