【VIM 入门到精通】快速查找与替换:定位和修改文本的利器

第4节:快速查找与替换:定位和修改文本的利器

引言

想象一下,你正在处理一个庞大的代码项目,或者一篇长篇技术文档。突然,你需要将文件中所有的某个旧函数名替换为新函数名,或者查找某个特定的错误日志并批量修改。如果只能一行一行、一个字一个字地手动查找和修改,那效率将是灾难性的!

别担心!Vim 作为一款高效的文本编辑器,其强大的查找和替换功能,就像是赋予了你"千里眼"和"神之手",让你能够瞬间定位到目标内容,并以闪电般的速度进行批量修改。本节课,我们将一同揭开Vim查找与替换的神秘面纱,让定位和修改文本不再是你的难题!

核心知识点

Vim 的查找与替换主要通过命令模式 下的命令和底行模式下的操作来实现。

一、快速查找:文本中的"千里眼"

查找是编辑文本的基础,Vim 提供了多种灵活的查找方式。

1. 基本查找

在命令模式下,我们可以使用 /? 命令进行查找。

  • /pattern :在当前光标位置向下 (向文件尾部)查找指定的 pattern (模式)。
  • ?pattern :在当前光标位置向上 (向文件头部)查找指定的 pattern

例如,要查找文件中的所有 "main" 关键字,你只需输入 /main 并回车。

vim 复制代码
/main     " 向下查找第一个 'main'
?error    " 向上查找第一个 'error'
2. 导航查找结果

找到第一个匹配项后,你还需要在不同的匹配项之间跳转。

  • n :重复上一次的查找操作,沿同一方向跳转到下一个匹配项。
  • N :重复上一次的查找操作,沿相反方向跳转到上一个匹配项。

这意味着,如果你用 / 查找后,n 会继续向下找,N 会向上找;如果你用 ? 查找后,n 会继续向上找,N 会向下找。

3. 高亮显示查找结果

默认情况下,Vim 可能不会高亮显示所有匹配项。高亮显示可以让你一眼看到所有查找到的内容,非常实用。

  • :set hlsearch:开启高亮显示查找结果。
  • :set nohlsearch:关闭高亮显示。
  • :noh:nohlsearch :快速清除当前查找的高亮显示,但下次查找时仍会高亮(因为 hlsearch 设置未改变)。

要让 hlsearch 永久生效,可以将其添加到你的 ~/.vimrc 配置文件中。

vim 复制代码
:set hlsearch   " 开启查找结果高亮
:set nohlsearch " 关闭查找结果高亮
:noh            " 清除当前高亮,但不改变设置
4. 快速按单词查找

当你想要查找光标下的完整单词时,Vim 提供了更快捷的方式。

  • * :向 查找光标所在处的完整单词(会自动添加单词边界,例如 \<word\>)。
  • # :向查找光标所在处的完整单词。

这在编程时非常方便,例如,光标在一个变量名上时,按 * 可以迅速找到所有使用该变量的地方。

vim 复制代码
" 光标在 'myVariable' 上时
*   " 向下查找完整的 'myVariable' 单词
#   " 向上查找完整的 'myVariable' 单词
5. 正则表达式在查找中的应用

Vim 的查找功能支持强大的正则表达式(Regular Expressions, regex)。掌握正则表达式能让你进行更复杂的模式匹配。Vim 的正则表达式语法与 Perl 兼容的正则表达式有所不同,但核心概念是相通的。

以下是一些常用的 Vim 正则表达式元字符:

元字符 含义 示例 匹配
. 匹配任意单个字符 (除了换行符) /a.b axb, a!b
* 匹配前一个字符或模式零次或多次 /a*b b, ab, aaab
\+ 匹配前一个字符或模式一次或多次 /a\+b ab, aaab (不匹配 b)
\? 匹配前一个字符或模式零次或一次 /a\?b b, ab
^ 匹配行首 /^start 匹配以 start 开头的行
$ 匹配行尾 /end$ 匹配以 end 结尾的行
\< 匹配单词开头 /\<word 匹配 word 在单词开头的 wordplay
\> 匹配单词结尾 /word\> 匹配 word 在单词结尾的 myword
[] 匹配括号内的任意一个字符 /[aeiou] 匹配任意一个小写元音字母
[^] 匹配除了括号内字符以外的任意一个字符 /[^0-9] 匹配任意非数字字符
\d 匹配任意数字 (等同于 [0-9]) /\d\+ 匹配一个或多个数字,如 123, 45
\w 匹配任意单词字符 (字母、数字、下划线) /\w\+ 匹配一个或多个单词字符,如 hello_world
\s 匹配任意空白字符 (空格、Tab 等) /\s\+ 匹配一个或多个空白字符
\ 转义字符,将特殊字符转为普通字符,或将普通字符转为特殊字符 /\. /\* 匹配字面量 .,匹配字面量 *
\v "very magic" 模式:使多数字符默认解释为正则表达式特殊字符,减少转义 /\v(ab)+ 匹配 ab 一次或多次,括号无需转义 \( \)

注意: Vim 的正则表达式默认是 magic 模式,这意味着 *, . 等字符会被解释为特殊字符。如果你想匹配它们本身,需要用 \ 进行转义,如 /\* 匹配星号。使用 \v (very magic) 模式可以让你在写正则表达式时减少转义,因为大多数非字母数字字符都会被视为特殊字符。

vim 复制代码
" 查找以 'function' 开头,后面跟着一个或多个空白字符和任意单词字符的模式
/\vfunction\s+\w+ " 使用 \v 模式,\s 和 \w 无需转义,+ 也不需转义

" 查找所有以数字开头的行
/^\d.* " ^ 匹配行首,\d 匹配数字,. 匹配任意字符,* 匹配零次或多次
二、强大替换功能:文本中的"神之手"

查找的目的是为了修改。Vim 的替换功能非常强大,可以通过 s (substitute) 命令实现。其基本语法为:

:[range]s/{pattern}/{replacement}/[flags]

  • ::进入底行命令模式。
  • [range]:替换的范围。
  • s:substitute 命令,表示替换。
  • {pattern}:要查找的模式,可以使用正则表达式。
  • {replacement}:要替换成的内容,也可以包含特殊字符(如捕获组)。
  • [flags]:控制替换行为的标志位。
1. 替换范围 [range]
  • (空):只作用于当前行。
  • n :只作用于第 n 行。
  • n,m :作用于第 n 行到第 m 行(包含 nm)。例如 10,20s/old/new/g
  • % :作用于整个文件(所有行)。这是最常用的全局替换范围,等同于 1,$。例如 :%s/old/new/g
  • .,$:作用于当前行到文件末尾。
  • '<,'> :作用于可视模式(Visual mode)下选中的区域。进入可视模式(例如按 v 键),选中一段文本后,按下 :,Vim 会自动填充为 :'<,'>
vim 复制代码
:s/foo/bar/    " 替换当前行第一个 'foo' 为 'bar'
:10s/foo/bar/g " 替换第 10 行所有 'foo' 为 'bar'
:10,20s/foo/bar/g " 替换第 10 到 20 行所有 'foo' 为 'bar'
:%s/foo/bar/g  " 替换整个文件所有 'foo' 为 'bar'
:'<,'>s/foo/bar/g " 替换选定区域所有 'foo' 为 'bar'
2. 替换标志 [flags]

这些标志位放在替换命令的末尾,用于控制替换的细节。

  • g (global) :全局替换。在一行中替换所有匹配项,而不是只替换第一个。非常常用! 如果没有 g,每行只会替换第一个匹配到的内容。
  • c (confirm) :确认替换。Vim 会在每次替换前询问你是否执行。这对于不确定是否所有匹配项都应该被替换时非常有用。
    • y:替换当前匹配项。
    • n:跳过当前匹配项。
    • a:替换当前及后续所有匹配项(不再询问)。
    • q:退出替换。
    • l:替换当前匹配项并退出。
  • i (ignorecase) :忽略大小写。查找 pattern 时不区分大小写。
  • I (noignorecase) :不忽略大小写。强制区分大小写,即使 :set ignorecase 被设置。
  • n (number):不执行替换,只显示匹配的次数。这可用于"试运行",看看有多少地方会受影响。
  • & :重复上一次的 s 命令。
vim 复制代码
:%s/old_var/new_var/g  " 全文件替换所有 'old_var' 为 'new_var'
:%s/bug/fix/gc         " 全文件替换 'bug' 为 'fix',每次替换前确认
:%s/Error/Warning/gi   " 全文件替换 'Error' (不区分大小写) 为 'Warning'
3. 替换内容中的特殊字符

{replacement} 部分,你也可以使用一些特殊符号:

  • &\0 :表示整个匹配到的 pattern 本身。
  • \1, \2, ... \9 :表示正则表达式中捕获组(\(\) 包裹的部分)匹配到的内容。这是正则表达式替换的精髓!
vim 复制代码
" 将所有 'function myFunction' 替换为 'func myFunction'
:%s/\vfunction\s+(\w+)/func \1/g
" \v 使得 ( ) 不用转义,(\w+) 捕获函数名,\1 则引用捕获到的函数名
4. 交互式替换的另外一个技巧 cgn

除了 :%s///gc 之外,Vim 还提供了一种更灵活的交互式替换工作流。

  1. 首先,使用 /* 命令查找你想要替换的模式。
  2. 找到第一个匹配项后,光标停留在该位置。
  3. 输入 cgn:这会删除当前匹配项并进入插入模式,你可以输入新的替换内容。
  4. 输入替换内容后,按 Esc 退回普通模式。
  5. 现在,你可以:
    • n 跳转到下一个匹配项。
    • . (点号) 重复上一次的 cgn 替换操作。
    • 再次按 cgn 进行不同的替换。

这种方式的好处在于,你可以逐个查看匹配项,决定是否替换,并且每次替换的内容可以不同。

代码/案例演示

让我们通过几个实际案例来巩固所学知识。

案例一:快速查找特定函数调用

假设你有一个 C++ 项目,想快速找到所有 calculate_total() 函数的调用。

cpp 复制代码
// 示例文件: main.cpp
#include <iostream>

int calculate_total(int a, int b) {
    return a + b;
}

void print_result(int res) {
    std::cout << "Result: " << res << std::endl;
}

int main() {
    int x = 10, y = 20;
    int sum = calculate_total(x, y); // 第一次调用
    print_result(sum);

    // 更多代码...
    int another_sum = calculate_total(5, 7); // 第二次调用
    print_result(another_sum);

    return 0;
}
  1. 打开文件

    bash 复制代码
    vim main.cpp
  2. 查找 calculate_total
    在命令模式下,输入 /calculate_total 并回车。

    vim 复制代码
    /calculate_total

    Vim 会跳转到第一个 calculate_total

  3. 高亮显示并导航

    vim 复制代码
    :set hlsearch " 确保高亮开启,方便查看
    n             " 跳转到下一个匹配项
    n             " 继续跳转
    N             " 返回上一个匹配项
  4. 按单词查找(光标在 calculate_total 上时)

    vim 复制代码
    * " 直接查找光标下的完整单词,并跳转到下一个
    # " 向上查找光标下的完整单词,并跳转到上一个
案例二:批量修改变量名

你需要将文件中的旧变量名 old_value 全部修改为 new_data

python 复制代码
# 示例文件: script.py
def process_data(old_value):
    temp_value = old_value * 2
    if temp_value > 100:
        print(f"High old_value: {old_value}")
    return old_value / 2

my_data = 50
result = process_data(my_data)
# old_value 在注释中
print(f"Final result with old_value: {result}")
  1. 全文件替换(无确认)

    vim 复制代码
    :%s/old_value/new_data/g
    • %:表示作用于整个文件。
    • s:替换命令。
    • /old_value/:要查找的模式。
    • /new_data/:替换成的内容。
    • g:表示替换每一行中所有匹配项。
      执行后,所有 old_value 都会被替换,包括注释中的,这可能不是我们想要的。
  2. 全文件替换(带确认)

    为了避免误伤,我们使用 c 标志进行确认。

    vim 复制代码
    :%s/old_value/new_data/gc
    • Vim 会逐个高亮匹配项,并在底行询问 replace with new_data (y/n/a/q/l/^E/^Y)?
    • 你可以根据情况输入 y (yes), n (no), a (all), q (quit) 等。
  3. 交互式替换(cgn 方式)

    这是一种更精细的控制方式,尤其适合当你只想替换一部分匹配项,或者替换内容可能不同时。

    a. 首先,查找 old_value

    vim 复制代码
    /old_value

    b. Vim 会跳转到第一个 old_value。如果这是你想要替换的,输入 cgn,然后输入 new_data 并按 Esc

    vim 复制代码
    cgn new_data<Esc> " 替换并回到命令模式

    c. 按 n 跳转到下一个 old_value

    d. 如果下一个也想替换成 new_data,直接按 . (点号) 即可重复上次的替换操作。

    e. 如果遇到注释中的 old_value,按 n 跳过它。

    f. 继续 n.,直到完成所有替换。

案例三:使用正则表达式进行高级替换

假设你有一个日志文件,其中包含日期格式 YYYY-MM-DD,现在想把它修改为 MM/DD/YYYY

log 复制代码
# 示例文件: server.log
2023-01-15 - Server started.
User logged in from 192.168.1.10 at 2023-01-15 10:30:00.
2023-01-16 - Processing data...
Error occurred on 2023-01-16.

这里我们需要使用捕获组。

  1. 分析模式
    YYYY-MM-DD 格式可以拆分为三部分:

    • YYYY:四位数字 (\d{4})
    • MM:两位数字 (\d{2})
    • DD:两位数字 (\d{2})
  2. 构建替换命令

    vim 复制代码
    :%s/\v(\d{4})-(\d{2})-(\d{2})/\2\/\3\/\1/g
    • %s:全文件替换。
    • \v:开启 "very magic" 模式,使得 ( ) + 等无需转义。
    • (\d{4}):捕获四位数字作为第一组(年)。
    • (\d{2}):捕获两位数字作为第二组(月)。
    • (\d{2}):捕获两位数字作为第三组(日)。
    • -:匹配字面量破折号。
    • /\2\/\3\/\1/:替换部分,\2 引用捕获的月,\3 引用捕获的日,\1 引用捕获的年。注意 / 需要用 \ 转义,因为 / 是分隔符。
    • g:全局替换。

执行后,日志文件内容将变为:

log 复制代码
01/15/2023 - Server started.
User logged in from 192.168.1.10 at 01/15/2023 10:30:00.
01/16/2023 - Processing data...
Error occurred on 01/16/2023.

小贴士: 当查找或替换的 patternreplacement 中包含 / 字符时,你可以选择使用其他非字母数字字符作为分隔符,例如 |#!,这样就不用转义 / 了。

例如,将 /usr/local/bin 替换为 /opt/homebrew/bin

vim 复制代码
:%s#/usr/local/bin#/opt/homebrew/bin#g
" 使用 '#' 作为分隔符,无需转义 '/'

总结

恭喜你!到这里,你已经掌握了 Vim 查找与替换的核心技能。让我们回顾一下本节课的重点:

  • 基本查找 :使用 / 向下查找,? 向上查找。
  • 导航结果 :使用 nN 在匹配项之间跳转。
  • 高亮显示:set hlsearch 开启高亮,:noh 清除当前高亮。
  • 按单词查找*# 快速查找光标下的完整单词。
  • 正则表达式 :了解并运用元字符 (., *, ^, $, \d, \w, []) 和 \v 模式进行高级模式匹配。
  • 基本替换:[range]s/{pattern}/{replacement}/[flags] 命令结构。
  • 替换范围 :掌握 (空)n,m%:'<,'> 等不同范围的用法。
  • 替换标志 :熟练运用 g (全局)、c (确认)、i (忽略大小写) 等标志。
  • 捕获组 :在替换内容中使用 &\1, \2 等引用匹配到的内容。
  • 交互式替换 :利用 / 配合 cgn. 进行灵活的逐个确认替换。

Vim 的强大之处在于它极大的灵活性和可定制性。查找与替换作为其中的核心功能,更是你提高工作效率不可或缺的利器。实践是掌握任何技能的最好方法,所以,请立即打开 Vim,在你的代码或文档中尽情尝试这些命令吧!

下一节课,我们将继续探索 Vim 的更多奥秘!

相关推荐
七元权1 小时前
VSCode连接远程容器失败(Missing GLIBC >=2.28!)
ide·vscode·编辑器·连接容器
infiniteWei1 小时前
【VIM 入门到精通】视觉模式与剪贴板:高效选择、复制与粘贴
linux·编辑器·vim
追风少年ii1 小时前
脚本测试--R版本 vs python版本的harmony整合效果比较
linux·python·机器学习·空间·单细胞·培训
infiniteWei1 小时前
【VIM 入门到精通】精准光标移动与文本对象:Vim思维的进阶
linux·编辑器·vim
南猿北者1 小时前
go环境搭建--Linux
linux·开发语言·golang
小糖学代码10 小时前
LLM系列:1.python入门:3.布尔型对象
linux·开发语言·python
shizhan_cloud10 小时前
Shell 函数的知识与实践
linux·运维
Deng87234734810 小时前
代码语法检查工具
linux·服务器·windows
信奥胡老师11 小时前
苹果电脑(mac系统)安装vscode与配置c++环境,并可以使用万能头文件全流程
c++·ide·vscode·macos·编辑器