change

change.txt 适用于 Vim 9.2 版本。 最近更新: 2026年2月 VIM 参考手册 by Bram Moolenaar 译者: Willis 本文档介绍用于删除和修改文本的命令。本文中的修改文本是指通过单个命令删除部分文 本并将其替换成其他文本。本文所述所有命令都支持撤销。其中非命令行 (Ex) 命令可用 "." 命令重复执行。 1. 删除文本 deleting 2. 删除并插入 delete-insert 3. 简单修改 simple-change changing 4. 复杂修改 complex-change 4.1 过滤命令 filter 4.2 替代 :substitute 4.3 搜索并替代 search-replace 4.4 调整制表 change-tabs 5. 复制和移动文本 copy-move 6. 文本排版 formatting 7. 文本排序 sorting 8. 文本去重 deduplicating 关于插入文本部分,参阅 insert.txt

1. 删除文本 deleting E470

["x]<Del> <Del> x dl ["x]x 删除 [count] 个光标所在及之后的字符 [到寄存器 x] (非 linewise 行动作)。和 "dl" 相同。 <Del> 键不使用 [count] 计数。如果给出计数,其作用是删 除该计数的最后一位。 如果 <Del> 键行为与预期不符,参见 :fixdel 。要用于删 除换行符 (合并行),参见 'whichwrap' X dh ["x]X 删除 [count] 个光标之前的字符 [到寄存器 x] (非 linewise 行动作)。和 "dh" 相同。另见 'whichwrap' d ["x]d{motion} 删除 {motion} 动作覆盖的文本 [到寄存器 x]。例外见下。 dd ["x]dd 删除 [count] 行 [到寄存器 x], linewise 行动作。 D ["x]D 删除光标所在字符到当前行尾,并向后删除 [count]-1 行 [到寄存器 x] (非 linewise 行动作)。和 "d$" 同义。 'cpoptions' 里包含 '#' 标志位时 ( cpo-# ),忽略计数。 {Visual}["x]x 或 v_x v_d v_<Del> {Visual}["x]d 或 {Visual}["x]<Del> 可视模式下,删除高亮文本 [到寄存器 x] (关于 {Visual}, 参见 Visual-mode )。 {Visual}["x]CTRL-H v_CTRL-H v_<BS> {Visual}["x]<BS> 选择模式下,删除高亮文本 [到寄存器 x]。 {Visual}["x]X 或 v_X v_D v_b_D {Visual}["x]D 可视模式下,删除高亮行 [到寄存器 x] (关于 {Visual},参 见 Visual-mode )。可视列块模式下,"D" 删除高亮文本, 以及直到行尾的所有内容。 :d :de :del :delete :dl :dp :[range]d[elete] [x] 删除 [range] 范围内的所有行 (缺省: 当前行) [到寄存器 x]。 注意这些奇异的缩写形式: :dl 删除并列出 ( :list ) :dell 同上 :delel 同上 :deletl 同上 :deletel 同上 :dp 删除并显示 ( :print ) :dep 同上 :delp 同上 :delep 同上 :deletp 同上 :deletep 同上 :[range]d[elete] [x] {count}[range] 范围的结束行 (缺省: 当前行) 开始,删除 {count} 行 [到寄存器 x]。参见 cmdline-ranges 。 这些命令用于删除文本。除 :d 外,可用 . 命令重复执行,且所有删除操作均可撤 销。在可视模式下可以删除列块文本。有关寄存器的说明,参见 registers d-special d{motion} 命令的特例: 当动作不面向行、动作的起始和结束位置不在同一行、起始位置 之前只有空白、且结束位置之后没有非空白字符时,该删除会自动转为行动作。这可能会 删除原先想保留的空白行。要关闭此特殊行为,可用 o_v 操作符强制该动作面向字 符,或从 'cpoptions' 里删除 "z" 标志位 (见 cpo-z )。 'cpoptions' 包含 'E' 标志位时,如果试图删除空文本区域 (如在首列上按 "d0"),报 错。 J J 合并 [count] 行,但至少包含两行。移除缩进,插入不超过 两个空格 (见下)。在缓冲区末行执行此操作会失败。[count] 如果过大,会自行缩减为剩余可用行数。 v_J {Visual}J 可视模式下,合并高亮行,但至少包含两行。移除缩进,插入 不超过两个空格 (见下)。 gJ gJ 合并 [count] 行,但至少包含两行。不插入也不删除任何空 格。 v_gJ {Visual}gJ 可视模式下,合并高亮行,但至少包含两行。不插入也不删除 任何空格。 :j :join :[range]j[oin][!] [flags] 合并 [range] 范围内的所有行。和 "J" 相同,但添加 [!] 时,合并操作不插入也不删除任何空格。缺省合并当前行与下 一行。 如果 [range] 的起始行和结束行相同,命令不执行任何操 作。 [flags] 可见 ex-flags 。 :[range]j[oin][!] {count} [flags] 合并 [range] 范围的结束行 (缺省: 当前行) 开始的 {count} 行。参见 cmdline-ranges 。和 "J" 相同,但添加 [!] 时,合并不插入也不删除任何空格。 [flags] 可见 ex-flags 。 这些命令会删除行间的 <EOL> (换行符),其实际效果是使多行合并成一行。除 :j 外,可用 . 命令重复执行,且所有操作均可撤销。 非 "gJ" 系列的命令会插入一个空格以替换 <EOL>,除非当前行末尾已有空白字符,或下 一行以 ')' 开头。非 "gJ" 系列的命令同时会删除下一行的所有起始空白。打开 'joinspaces' 选项时,这些命令在 '.'、'!' 或者 '?' 后插入两个空格而非一个 (但当 'cpoptions' 包括 'j' 标志位时,仅在 '.' 后插入两个空格)。 'formatoptions' 中的 'B' 和 'M' 标志位会修改多字节字符前后的空格插入行为,参见 fo-table'[ 标记指向被合并行首行的原行尾位置, '] 标记指向合并后的最终行尾。

2. 删除并插入 delete-insert replacing

R R 进入替换模式: 从光标所在位置开始,每输入一个字符就替换 一个已有字符。然后将输入文本重复 [count]-1 次。详见 Replace-mode gR gR 进入虚拟替换模式: 每输入一个字符就替换占据相同屏幕空间 的已有字符 (一个 <Tab> 从而可以可一次性替换多个字符)。 然后将输入文本重复 [count]-1 次。详见 Virtual-Replace-mode c ["x]c{motion} 删除 {motion} 覆盖的文本 [到寄存器 x],然后进入插入模 式。'cpoptions' 包含 'E' 标志位时,如果无实际文本可删 除 (如执行 "cTx" 但光标位于 'x' 之后),会报错并拒绝进 行插入模式 (这与 Vi 兼容)。反之当 'cpoptions' 不包含 'E' 时,"c" 命令无论是否删除文本都会启动插入模式。 cc ["x]cc 删除 [count] 行 [到寄存器 x],然后进入插入模式。 linewise 行动作。置位 'autoindent' 时,会保留首行的 缩进。 C ["x]C 从光标位置删除到行尾,并向后删除 [count]-1 行 [到寄存 器 x],然后进入插入模式。和 c$ 等价 (非 linewise 行 动作)。 s ["x]s 删除 [count] 个字符 [到寄存器 x],然后进入插入模式。(s 代表替代 (Substitute))。和 "cl" 等价 (非 linewise 行 动作)。 S ["x]S 删除 [count] 行 [到寄存器 x],然后进入插入模式。和 "cc" 等价。 linewise 行动作。 {Visual}["x]c or v_c v_s {Visual}["x]s 可视模式下,删除高亮文本 [到寄存器 x],然后进入插入模 式 (关于 {Visual},参见 Visual-mode )。 v_r {Visual}r{char} 可视模式下,将所有高亮字符替换为 {char}CTRL-C 按本义插入。 v_C {Visual}["x]C 可视模式下,删除高亮行 [到寄存器 x],然后进入插入模 式。可视列块模式下,行为有所不同,见 v_b_C v_S {Visual}["x]S 可视模式下,删除高亮行 [到寄存器 x],然后进入插入模式 (关于 {Visual},参见 Visual-mode )。 v_R {Visual}["x]R 当前功能和 {Visual}["x]S 相同。后续版本可能会发生变 动。 备注: - 可用 <Esc> 退出插入和替换模式。 - 要了解这些模式下的其他特殊字符,可见 "插入和替换模式" 一节 mode-ins-repl 。 - [count] 的效果只有在 Vim 退出插入或替换模式时才会生效。 - 当 'cpoptions' 选项包含 '$' 时,如果修改仅在一行内进行,Vim 会继续显示已删除 的文本,并在最后一个被删字符后显示 '$'。新插入的文本会覆盖被修改的文本。 有关寄存器的说明,参见 registers 。 替换模式和插入模式类似,区别在于每输入一个字符会同时删除一个原有字符。如果到达 行尾,Vim 会将后续输入的字符追加到行尾 (和插入模式相同)。在替换模式下,退格键 可恢复原有文本 (如有)。(参见 "插入和替换模式" 一节 mode-ins-repl )。 cw cW 特例: 光标在单词内部时,"cw" 和 "cW" 不会包含单词后的空白,而只修改到词尾。这 是因为 Vim 把 "cw" 解释为 修改-单词,而单词本身并不包括其后的空白。 {Vi 兼容: 如果光标在空白字符上且其后仍有空白字符,"cw" 只修改第一个空白;这属 于潜在漏洞,因为 "dw" 会删除所有空白;可通过 'cpoptions' 里的 'w' 标志位来恢复 Vi 兼容行为} 如果希望 "cw" 包含 单词后的空格,可用以下映射: :map cw dwi 还有一个方案,可用 "caw" (另见 awcpo-z )。 :c :ch :change :{range}c[hange][!] 用不同文本替换若干文本行。输入只包含一个 "." 的行来结 束替换文本的输入。{range} 省略时,该命令只置换当前行。 添加 [!] 后,会在本命令执行期间临时切换 'autoindent'。 此命令在 Vim9 脚本里不支持,因为极易和变量名产生混 淆。

3. 简单修改 simple-change

r r{char} 将光标所在字符替换为 {char}{char}<CR><NL> 时,则替换为换行符。要替换为真正的 <CR>,可输入 CTRL-V <CR>。而输入 CTRL-V <NL> 会替换为空字符 <Nul>{char}CTRL-ECTRL-Y 时,会复制下一行或上一行的 对应字符 (和插入模式一致, i_CTRL-Ei_CTRL-Y )。 支持计数,例如 10r<C-E> 会从下一行复制 10 个字符。 给出 [count] 时,Vim 会用 {char} 连续替换 [count] 个字 符。不过,如果 {char}<CR><NL>,Vim 只插入一个 换行符: 如 "5r<CR>" 会用一个换行符替换五个字符。 当 {char}<CR><NL> 时,Vim 会自动缩进。效果等同 于先删除要替换的字符,再执行 "i<CR><Esc>"。 {char} 支持输入二合字母 digraph-arg:lmap 映射会作用于 {char}。插入模式下的 CTRL-^ 命令 可切换此功能 i_CTRL-^'encoding' 为 Unicode 编码时,要使用组合字符,参见 utf-8-char-arg gr gr{char} 替换光标下的虚拟字符。替换操作基于屏幕显示位置,而非文 件实际存储位置。详见 gRVirtual-Replace-mode 。 和 r 一样,支持使用计数。{char} 输入方式也与 r 类 似,但不能使用插入模式下有特殊含义的字符,包括大部分 CTRL-组合键 digraph-arg 普通模式下,需要单字符参数的命令 (如 rt ),在 'cpo' 不包含 'D' 标志位 时,可通过 digraphs 方式输入该字符: 先按 CTRL-K 再输入二合字母对应的两个字符。 {仅当编译时加入 +digraphs 特性才有效} case 以下命令用于切换字母大小写。操作会使用当前生效的 locale 。参见 :language 。 这里会用到 LC_CTYPE 环境变量。 ~ ~ 打开 'notildeop' 时: 切换光标下字符的大小写,并将光标 右移。给出 [count] 时,对指定数量的字符执行此操作。 ~{motion}'tildeop' 时: 切换 {motion} 覆盖文本的大小写。 g~ g~{motion} 切换 {motion} 覆盖的文本的大小写。 g~g~ g~g~ g~~ g~~ 切换当前行的大小写。 v_~ {Visual}~ 可视模式下,切换高亮文本的大小写 (关于 {Visual},参见 Visual-mode )。 v_U {Visual}U 可视模式下,使高亮文本转为大写 (关于 {Visual},参见 Visual-mode )。 gU uppercase gU{motion} 使 {motion} 覆盖的文本转为大写。 例如: :map! <C-F> <Esc>gUiw`]a 在插入模式下 按 CTRL-F,可使光标之前的单词转为大写。这 方便输入大写单词,只要先输入小写,再一键转换即可。 gUgU gUgU gUU gUU 使当前行转为大写。 v_u {Visual}u 可视模式下,使高亮文本转为小写 (关于 {Visual},参见 Visual-mode )。 gu lowercase gu{motion} 使 {motion} 覆盖的文本转为小写。 gugu gugu guu guu 使当前行转为小写。 g? rot13 g?{motion} 用 Rot13 对 {motion} 覆盖的文本进行编码。 v_g? {Visual}g? 可视模式下,用 Rot13 对高亮文本进行编码 (关于 {Visual},参见 Visual-mode )。 g?g? g?g? g?? g?? 用 Rot13 对当前行进行编码。 要用标题大写 (title cap) 形式改写一行,即每个单词首字母大写,其余小写,可用: :s/\v<(.)(\w*)/\u\1\L\2/g 递 增 与 递 减 CTRL-A CTRL-A 将光标所在或后方的数值或字母增加 [count] v_CTRL-A {Visual}CTRL-A 可视模式下,将高亮文本内的数值或字母增加 [count] v_g_CTRL-A {Visual}g CTRL-A 可视模式下,将高亮文本内的数值或字母增加 [count]。如果 高亮跨越多行,每行将依次叠加额外的 [count] (即生成以 [count] 为步长的递增数列)。 例如,假定有如下数值列表: 1. 1. 1. 1. 将光标移动至第二个 "1.",可视选中后三行,按 g CTRL-A 会生成: 1. 2. 3. 4. CTRL-X CTRL-X 将光标所在或后方的数值或字母减去 [count] v_CTRL-X {Visual}CTRL-X 可视模式下,将高亮文本内的数值或字母减去 [count]。 MS-Windows 上,此键被映射到剪切可视文本 dos-standard-mappings 。要屏蔽该映射,可用: silent! vunmap <C-X> v_g_CTRL-X {Visual}g CTRL-X 可视模式下,将高亮文本内的数值或者字母减去 [count]。如 果高亮跨越多行,每行将依次多减一个 [count] (即生成以 [count] 为步长的递减数列)。 CTRL-ACTRL-X 命令可用于: - 带符号或无符号十进制数 - 无符号二进制、八进制和十六进制数 - 字母 具体应用的值取决于 'nrformats' 选项: - 当 'nrformats' 包括 "bin" 时,Vim 将 '0b' 或 '0B' 开头的数值识别为二进制。 - 当 'nrformats' 包括 "octal" 时,Vim 将 '0' 开头的数值识别为八进制,除非数位 里包含 '8' 或 '9'。其他数值默认为十进制,并可带负号。 如果光标已经在数值上,命令会操作该数值;否则操作光标右侧数值。 - 当 'nrformats' 包括 "hex" 时,Vim 将 '0x' 或者 '0X' 开头的数值识别为十六进 制。数值最右侧的字母决定结果使用的大小写。如果当前数值不包含字母,Vim 会沿用 上次检测到的大小写。 - 当 'nrformats' 包括 "alpha" 时,Vim 会对光标所在或后方的字母进行增减。这可用 于构造字母编号的列表。 增减操作只会考虑十进制形式的前导负号。而不会考虑二进制、八进制和十六进制形式。 要一律忽略正负号,可用可视模式选中数值本身。再执行 CTRL-ACTRL-X。 对于以零开头的数值 (包括八进制和十六进制),Vim 会尽可能保持字符总位数不变。 例如,在 "0077" 上执行 CTRL-A 会返回 "0100",在 "0x100" 上执行 CTRL-X 会返回 "0x0ff"。 特例: 'nrformats' 包含 "octal" 时,如果发现某数值以零开头但不是合法八进制 (因 为包含 '8' 或 '9'),会删除开头的零,以免结果被误认作八进制。 注意 'nrformats' 包含 "octal" 时,以零开头的十进制数会被错误识别,因为 会与八进制数混淆。 同样需要 注意'nrformats' 同时包含 "bin" 和 "hex" 时,以 '0x' 或 '0X' 开头的 二进制数会被识别为十六进制,因为 '0b' 属于合法的十六进制字符。例如,在 "0x0b11" 上执行 CTRL-A 会返回 "0x0b12" 而非 "0x0b100"。 而当 'nrformats' 包含 "bin" 但不包含 "hex" 时,在 "0x0b11" 的 "0b11" 上执行 CTRL-A 会返回 "0x0b100"。 如果光标所在的数值超出了 32 或 64 位 (取决于 Vim 的编译方式) 可表示范围,会取 整到最接近的可表示数值,并忽略本次增减操作。例如,在 64 位环境下,在 18446744073709551616 上执行 CTRL-X 会返回 18446744073709551615。对更大的数值如 18446744073709551618 上的操作,结果相同。 CTRL-A 命令在宏命令里很有用。例如: 可按以下步骤可构造带数字编号的列表。 1. 建立首个列表项。确保以数值开头。 2. qa - 用寄存器 'a' 开始录制宏 3. Y - 抽出当前列表项 4. p - 将当前列表项的副本放置到下一行 5. CTRL-A - 递增计数 6. q - 停止录制宏 7. <count>@a - 重复抽出、放置和递增计数操作 <count> 次 将 文 本 左 移 或 右 移 shift-left-right < <{motion}{motion} 覆盖的多行左移 'shiftwidth' 列。 打开 'vartabstop' 特性且 'shiftwidth' 选项设为零时, 缩进量以行首第一个非空白字符为准计算。 << << 将 [count] 行左移 'shiftwidth' 列。 v_< {Visual}[count]< 可视模式下,将高亮行左移 [count]'shiftwidth' 列 (关于 {Visual},参见 Visual-mode )。 > >{motion}{motion} 覆盖的多行右移 'shiftwidth' 列。 打开 'vartabstop' 特性且 'shiftwidth' 选项设为零时, 缩进量以行首第一个非空白字符为准计算。 >> >> 将 [count] 行右移 'shiftwidth' 列。 v_> {Visual}[count]> 可视模式下,将高亮行右移 [count]'shiftwidth' 列 (关于 {Visual},参见 Visual-mode )。 :< :[range]< 将 [range] 指定的多行左移 'shiftwidth' 列。使用多个 '<' 可左移对应倍数的 'shiftwidth' 列。 :[range]< {count}[range] 范围的结束行 (缺省为当前行) 开始的 {count} 行左移 'shiftwidth' 列。参见 cmdline-ranges 。使用多 个 '<' 可左移对应倍数的 'shiftwidth' 列。 :[range]le[ft] [indent][range] 指定的多行左对齐。缩进量设为 [indent] (缺省 为 0)。 :> :[range]> [flags][range] 指定的多行右移 'shiftwidth' 列。使用多个 '>' 可右移对应倍数的 'shiftwidth' 列。 [flags] 部分可参见 ex-flags 。 :[range]> {count} [flags][range] 范围的结束行 (缺省为当前行) 开始的 {count} 行右移 'shiftwidth' 列。参见 cmdline-ranges 。使用多 个 '>' 可右移对应倍数的 'shiftwidth' 列。 [flags] 部分可参见 ex-flags 。 ">" 和 "<" 命令可方便地调整代码缩进。缩进的白数量由 'shiftwidth' 选项控制。通 常 'shiftwidth' 为 8,但也可设为 3 等更小的值。 如果已经没有缩进可减少,左移命令会停止。而右移命令不会对空白行产生影响。 打开 'shiftround' 选项时,缩进量会被取整为 'shiftwidth' 的整数倍。 打开 'smartindent' 选项、或打开 'cindent''cinkeys' 包含带零值的 '#' 时,右 移操作不会对 '#' 开头的行产生影响 (这类通常是 C 语言预处理行,'#' 应保持在第一 列)。可通过 'cino' 选项改变此行为,参见 cino-#'expandtab' 选项关闭 (缺省) 时,Vim 会尽量用 <Tab> 填充缩进。可用 ">><<" 将缩 进中的空格尽可能替换为 <Tab> 并保持缩进量不变 (必要时辅以少量空格)。而 'expandtab' 选项打开时,Vim 只使用空格缩进。此时 ">><<" 可将 <Tab> 替换成空格 (也可用 :retab! )。 要一次缩进多倍的 'shiftwidth' 列,可用可视模式或 : 命令。示例: Vjj4> 将三行右移四个缩进位 :<<< 将当前行左移三个缩进位 :>> 5 将五行右移两个缩进位 :5>> 将第五行右移两个缩进位

4. 复杂修改 complex-change

4.1 过滤命令 filter 过滤程序是指接受文本作为标准输入,进行某些修改,再将结果输出到标准输出的程序。 可用下列命令将文本发送给过滤程序,并用其输出结果替换原文本。过滤程序的例子包括 "sort",用于对行按字母顺序排序;还有 "indent",用于格式化 C 程序文件 (需要能以 过滤程序方式工作的版本,并非所有的版本都支持)。'shell' 选项指定 Vim 用于执行过 滤程序的外壳程序 (另见 'shelltype' 选项)。可用 "." 重复上一次的过滤命令。Vim 不会识别 :! 命令后面以 '"' 开头的注释。 ! !{motion}{filter} 用外部程序 {filter} 过滤 {motion} 覆盖的多行。 !! !!{filter} 用外部程序 {filter} 过滤 [count] 行。 v_! {Visual}!{filter} 可视模式下,用外部程序 {filter} 过滤高亮行 (关于 {Visual},参见 Visual-mode )。 :{range}![!]{filter} [!][arg] :range! 要执行外部命令,参见 :! 。 用外部程序 {filter} 过滤 {range} 指定的多行文本。Vim 会将可选的感叹号替换成最后给出的命令,并追加可选参数 [arg]。Vim 把过滤命令的输出保存到临时文件,并将该文件 内容读入缓冲区 tempfile 。Vim 使用 'shellredir' 选项把过滤程序的结果重定向到临时文件。不过,如果关闭了 'shelltemp' 选项且环境支持 (如 Unix 系统),则使用管道 机制。 'cpoptions' 里包含 'R' 标志位时,除非使用了 :keepmarks 命令,否则会删除被过滤行里的位置标记。例 如: :keepmarks '<,'>!sort 如果过滤后行数变少,被删除行里的位置标记无论如何都不会 保存。 = ={motion}'equalprg' 选项指定的外部程序过滤 {motion} 覆盖的多 行。'equalprg' 选项为空 (缺省) 时,使用内置排版机制 C-indenting'lisp'。不过,'indentexpr' 非空时,会 改用 indent-expression 缩进表达式机制。反之,如果 Vim 编译时没有包含内置排版机制,最终会使用外部的 "indent" 程序作为备用方案。 == == 用 ={motion} 类似的方式过滤 [count] 行。 v_= {Visual}= 可视模式下,用 ={motion} 类似的方式过滤高亮行。 tempfile setuid Vim 使用临时文件来处理过滤、执行比较和用于 tempname() 函数。Unix 上,该文件会 放在一个私有目录里 (仅当前用户可访问),以防堵安全漏洞 (如符号链接攻击或文件被 其他用户读取等)。Vim 退出时,会自动删除该目录及其下所有文件 (仅对 Unix 有效, 其它系统需要自行清理)。如果 Vim 自身设置了 setuid 位,这种方式可能会出问题。因 为临时文件归 setuid 用户拥有,但过滤程序会使用原用户的权限运行。 Vim 会在以下目录中按顺序选择首个可用的目录来创建临时文件: Unix: $TMPDIR、/tmp、当前目录、$HOME Windows: $TMP、$TEMP、c:\TMP、c:\TEMP MS-Windows 上,使用 GetTempFileName() 系统函数来生成临时文件。 其它系统上,则使用 tmpnam() 库函数。 4.2 替代 :substitute :s :su :[range]s[ubstitute]/{pattern}/{string}/[flags] [count][range] 指定的每一行,将 {pattern} 的匹配项用 {string} 替代。 关于 {pattern},参见 pattern{string} 可以是按本义出现的字符串,也可包含特殊字符。 参见 sub-replace-special[range][count] 都省略时,仅对当前行进行替代。 [count] 给出时,对 [range] 范围的结束行开始的 [count] 行进行替代。[range] 省略时,从当前行开始。 E939 E1510 [count] 必须为正值 (最大值 2147483647)。 另见 cmdline-ranges 。 关于 [flags],参见 :s_flags 。 可用 / 之外的其他字符作为定界符,参见 pattern-delimiter 。 :[range]s[ubstitute] [flags] [count] :[range]&[&][flags] [count] :& 重复执行最近一次 :substitute ,使用相同的匹配模式及替 代字符串,但不保留原有标志位。可在命令后追加 [flags] (见 :s_flags )。 注意 :substitute 后不能使用 '&' 和 '#' 标志位。因为 它们会被识别为模式定界符。 :substitute 和 'c'、'g'、'i'、'I' 和 'r' 标志位之间 的空格并非必需,但在脚本里建议保留,以免歧义。 另见下述用于重复 :substitute 的两字母和三字母命令 :substitute-repeat 。 :[range]~[&][flags] [count] :~ 重复执行最近一次 :substitute ,使用相同的替代字符串, 但使用最近使用的搜索模式作为匹配模式。相当于 :&r 。 关于 [flags],参见 :s_flags & & 相当于 :s (重复执行最近一次 :substitute )。注意 因 为不记住标志位,所以实际工作方式可能不尽相同。要保留原 有标志位,可用 :&& g& g& 相当于 :%s//~/& (在所有行上重复执行最近一次的 :substitute ,保留原有标志位,但使用前次匹配模式)。 例如,如果先执行替代命令 :s/pattern/repl/flags ,然后 执行 /search 搜索其他模式,此时 g& 会实际执行 :%s/search/repl/flags 。 助记: 全局 (global) 替代 (substitute)。 :snomagic :sno :[range]sno[magic] ... 和 :substitute 类同,但总使用 'nomagic' :smagic :sm :[range]sm[agic] ... 和 :substitute 类同,但总使用 'magic' :s_flags :substitute 命令里,可用以下标志位: :&& [&] 必须是首个标志位: 保留最近一次替代命令原有的标志位。例如: :&& :s/this/that/& 注意 不带此标志位时, :s:& 缺省不保留原有标志位。 [c] 确认每次替代。Vim 会高亮匹配的文本 (使用 hl-IncSearch )。确认时可输 入以下响应: :s_c 'y' 执行本次替代 'l' 执行本次替代后退出 (助记: "last",最后一次) 'n' 跳过本次匹配 <Esc> 退出替代 'a' 替代本次和其后所有匹配 'q' 退出替代 CTRL-E 上滚屏幕 CTRL-Y 下滚屏幕 打开 'edcompatible' 选项时,Vim 会记住 [c] 标志位并在下次使用时切换其 状态,在使用新的匹配模式时复位。 :s_e [e] 如果模式匹配失败,不给出错误信息,尤其在映射中继续执行,如同没发生错误 一样。常用于避免因无匹配项 ("No match") 错误中断映射。不过,Vim 不会屏 蔽以下错误信息: 正则表达式不能用字母作分界 \ 后面应该跟有 /、? 或 &" 没有前一个替代正则表达式 多余的尾部字符 已中断 :s_g [g] 替代当前行内所有匹配项。省略此标志位时,仅替代每行的首个匹配项。 打开 'edcompatible' 选项时,Vim 会记住 [g] 标志位并在下次使用时切换其 状态,在使用新的匹配模式时复位。打开 'gdefault' 选项时,缺省打开替代所 有匹配项的行为,而本标志位的作用是将其关闭。 :s_i [i] 模式忽略大小写。不考虑 'ignorecase''smartcase' 选项。 :s_I [I] 模式不忽略大小写。不考虑 'ignorecase''smartcase' 选项。 :s_n [n] 仅报告匹配次数,并不实际执行替代。[c] 标志位会被忽略。匹配结果会按 'report' 为零的方式显示。可用于 count-items 。 使用 \= sub-replace-expression 时,表达式会在 sandbox 里对每个匹配 求值。 [p] 显示最后一次替代所在的行。 :s_p [#] 和 [p] 类似,但在行首添加行号。 :s_# [l] 和 [p] 类似,但以 :list 方式显示文本。 :s_l :s_r [r] 仅能与无参数的 :&:s 配合使用。 :&r:~ 功能等价: 当匹配模 式为空时,使用最近使用的搜索模式,而非上次替代命令或 :global 命令的 模式。当然,如果最近执行的搜索命令就是替代或 :global 命令,两者没有 实际区别。如果最近是 "/" 那样的搜索命令,则使用该命令的模式。 带参数的 :s 则已默认如此: :s/blue/red/ /green :s//red/ 或 :~ 或 :&r 最后这些命令会把 "green" 替代成 "red"。而 :s/blue/red/ /green :& 最后这个命令会把 "blue" 替代成 "red"。 注意 没有用于改变模式 "魔术性" (magicness) 的标志位。为此,可改用其他命令,或 在模式中使用 /\v 之类项目。这是因为标志位只能在跳过模式之后才能被识别,而要 跳过模式,就必须先知道模式 "魔术性"。第二十二条军规! 替代命令所用的 {pattern} 为空时 (译者注: 如上所述,这只适用于无参数的替代命 令),会使用上次替代命令或 :global 命令的模式。如果没有这些,但存在上次搜索模 式,则使用该模式。而使用 [r] 标志位时,则会使用上次搜索模式,无论它来自替代、`: global` 或普通搜索命令。 省略 {string} 时,视为用空串替代。即删除匹配内容。此时,{pattern} 之后的分隔 符也可省略。例如: :%s/TESTING 会从所有行中删除首个 "TESTING"。 E1270 为兼容 Vi,老式脚本允许两种特例: "\/{string}/" 和 "\?{string}?" 等同于 "//{string}/r" (使用上次搜索模式)。 "\&{string}&" 等同于 "//{string}/" (使用上次替代命令或 :global 模式) (译者注:此处有误,两者并不相同,"//{string}/" 实际也使用上次搜索模式,见上)。 pattern-delimiter E146 E1241 E1242 包围模式和替代串的 '/' 也可改用其他单字节字符,这可用于搜索模式或替代串本身需 要使用 '/' 的场合。例如: :s+/+//+ 定界符可用大部分字符,但字母、数位、'\'、'"' 或 '|' 除外。在 Vim9 脚本里,也不 能用 '#',因为它可能被识别为注释开头。 模式的定义见 pattern 。在可视列块模式下,在模式中使用 /\%V 可使替代仅在列块 内生效,否则,替代会作用于整行。 sub-replace-special :s\= {string} 以 "\=" 开头时,会被作为表达式求值,参见 sub-replace-expression 。 可用于实现复杂替换或用特殊字符替代。替代操作的递归深度限制为 4 层。 E1290 :s% {string} 等于 "%",且 'cpoptions' 选项包含 '/' 时,会复用上次替代命令的替代 串 {string},见 cpo-/ 。 除此以外,{string} 字符串中包含的以下字符有特殊含义: magic nomagic 动作 & \& 替代为完整的匹配文本 s/\& \& & 替代为 & 字符 \0 替代为完整的匹配文本 \0 s/\0 \1 替代为第一个 () 里面的匹配文本 s/\1 \2 替代为第二个 () 里面的匹配文本 s/\2 .. .. s/\3 \9 替代为第九个 () 里面的匹配文本 s/\9 ~ \~ 替代为上次替代命令的替代字符串 s~ \~ ~ 替代为 ~ 字符 s/\~ \u 使下一个字符转为大写 s/\u \U 使其后字符转为大写,直到遇见 \E 为止 s/\U \l 使下一个字符转为小写 s/\l \L 使其后字符成为小写,直到遇见 \E 为止 s/\L \e 结束 \u、\U、\l 和 \L 的作用 (注意: 不是 <Esc>!) s/\e \E 同上 s/\E <CR> 在当前位置将该行拆分成两行 (<CR> 需按 CTRL-V <Enter> 输入) s<CR> \r 同上 s/\r \<CR> 插入回车符 (CTRL-M) (<CR> 需按 CTRL-V <Enter> 输入) s/\<CR> \n 插入 <NL> (对应文件中的 <NUL> 字符) (此处并非换行符) s/\n \b 插入 <BS> s/\b \t 插入 <Tab> s/\t \\ 插入单个反斜杠 s/\\ \x x 代表上面未列出的任意字符: 保留用于未来扩展 这里的特殊含义也适用于 substitute() 函数的第三个参数 {sub},但有以下差异: - % 总是插入百分号,与 'cpoptions' 无关。 - 总是假定有魔术性,与 'magic' 无关。 - ~ 总是插入波浪符。 - <CR> 和 \r 插入回车符 (CTRL-M)。 - \<CR> 没有特殊意义,只是 \x 之一。 示例: :s/a\|b/xxx\0xxx/g 将 "a b" 修改为 "xxxaxxx xxxbxxx" :s/\([abc]\)\([efg]\)/\2\1/g 将 "af fa bg" 修改为 "fa fa gb" :s/abcde/abc^Mde/ 将 "abcde" 修改为 "abc"、"de" (两行) :s/$/\^M/ 将 "abcde" 修改为 "abcde^M" :s/\w\+/\u\0/g 将 "bla bla" 修改为 "Bla Bla" :s/\w\+/\L\u\0/g 将 "BLA bla" 修改为 "Bla Bla" 注意: "\L\u" 可用于使单词整体转小写,仅首字母大写。此行为和 Vi 以及旧版 Vim 不 兼容,在旧版本中 "\u" 会抵消 "\L" 的效果。"\U\l" 同理。 注意: 在旧版中,CTRL-V 被特别处理。因为和 Vi 不兼容,该功能已被废弃,统一改用 反斜杠实现对应功能。 命令 文本 结果 :s/aa/a^Ma/ aa a<line-break>a :s/aa/a\^Ma/ aa a^Ma :s/aa/a\\^Ma/ aa a\<line-break>a (要输入 ^M,需按 CTRL-V <CR>) "\1","\2" 等序号对应模式里 "\(" 出现的先后顺序 (从左到右)。如果一个括号分组被 多次匹配,"\1","2" 等会取最后一次的匹配文本。例如: :s/\(\(a[a-d] \)*\)/\2/ 将 "aa ab x" 修改为 "ab x" "\2" 对应 "\(a[a-d] \)"。第一次匹配到 "aa ",第二次匹配到 "ab "。 括号分组和 '|' 组合使用时 (如 "\([ab]\)\|\([cd]\)"),两个模式必然有一个无法匹 配,所以 \1 或 \2 其中一个会为空。例如: :s/\([ab]\)\|\([cd]\)/\1x/g 将 "a b c d" 修改为 "ax bx x x" :sc :sce :scg :sci :scI :scl :scp :sg :sgc :sge :sgi :sgI :sgl :sgn :sgp :sgr :sI :si :sic :sIc :sie :sIe :sIg :sIl :sin :sIn :sIp :sip :sIr :sir :sr :src :srg :sri :srI :srl :srn :srp :substitute-repeat 2-字母和 3-字母的 :substitute 命令 这些命令用于重复执行最近一次的 :substitute 命令,并附加指定标志位。命令的首 字母总是 "s",后跟一到两个标志位字符。例如, :sce 相当于 :s///ce 。下表列出 所有合法组合,并非所有标志位组合都可用,因为有些组合是其他命令的缩写形式。 :substitute 命令速查表 | c e g i I n p l r | c :sc :sce :scg :sci :scI :scn :scp :scl | e | g :sgc :sge :sg :sgi :sgI :sgn :sgp :sgl :sgr | i :sic :sie :si :siI :sin :sip :sir | I :sIc :sIe :sIg :sIi :sI :sIn :sIp :sIl :sIr | n | p | l | r :src :srg :sri :srI :srn :srp :srl :sr 例外情况: :scr 代表 :scriptnames :se 代表 :set :sig 代表 :sign :sil 代表 :silent :sn 代表 :snext :sp 代表 :split :sl 代表 :sleep :sre 代表 :srewind 基于表达式的替代 sub-replace-expression sub-replace-\= s/\= 当替代字符串以 "\=" 开始时,其余部分会被解析为表达式。 除 "<CR>" 外, sub-replace-special 提到的字符特殊含义这里不再适用。<NL> 字符 会用于换行,在双引号字符串里也可用 "\n"。在 <NL> 之前加上反斜杠会插入真正的 <NL> 字符 (在文件里会以空字符 NUL 存储)。 "\=" 记法也可用于 substitute() 函数的第三个参数 {sub} 中,在那里, sub-replace-special 提到的字符特殊含义完全不适用。具体来说,<CR><NL> 不 会被用于换行,而分别被解析为按本义的回车符和换行符。 表达式执行结果为 List 时,列表项会用换行符连接。结果是每个列表项会成为独立一 行,列表项本身也可包含换行。 要获取匹配文本,可用 submatch() 函数。完整的匹配文本可用 "submatch(0)"。首个 括号分组的匹配文本可用 "submatch(1)",以此类推。 小心: 表达式中不能出现替代分隔符!建议使用 "@" 或者 ":" 这类字符。而执行结果中 出现分隔符不会产生问题。 例如: :s@\n@\="\r" .. expand("$HOME") .. "\r"@ 会把换行符替代为包含 $HOME 环境变量值的新行。 s/E/\="\<Char-0x20ac>"/g 会把所有的 'E' 字符替代为欧元符号。详见 <Char-> 。 4.3 搜索并替代 search-replace :pro :promptfind :promptf[ind] [string] 弹出搜索对话框。 [string] 给出时,会被用作对话框的初始 搜索字符串。 {仅适用于 Win32、Motif 和 GTK GUI 环境} :promptr :promptrepl :promptr[epl] [string] 弹出搜索/替代对话框。 [string] 给出时,会被用作对话框 的初始搜索字符串。 {仅适用于 Win32、Motif 和 GTK GUI 环境} 4.4 调整制表 change-tabs :ret :retab :retab! :[range]ret[ab][!] [-indentonly] [{new-tabstop}] 将所有包含 <Tab> 的空白序列,替换为使用 {new-tabstop} 定义的新制表位组成的空白序列。{new-tabstop} 省略或为 0 时,Vim 会使用当前制表位 'tabstop'。 已有的制表符则总是按 'tabstop' 当前值计算宽度。 带 ! 时,Vim 同时会把只包含正常空格的字符串在合适时尽 可能换成制表符。 置位 'expandtab' 时,Vim 会把所有的制表替换成等价的空 格。 本命令会先把 'tabstop' 设为 {new-tabstop}。在缺省对整 个文件执行时,视觉上排版不应有任何变化。 给出 [-indentonly] 时,只替换行首的缩进空白。不改变其 他位置 (行中、行尾) 的连续空白。 警告: 本命令会修改 C 程序中的字符串常量内部的 <Tab> 字 符。要避免这个问题,请使用 "\t" 代替 (这本身也是良好的 编程习惯)。 :retab! 也会把空格序列换成 <Tab>,这可能会破坏 printf() 等函数里的格式字符串。 打开 +vartabs 特性时,可用逗号分隔的列数值列表代替单 个制表位值。列表中每个值对应一个制表位宽度。末值除外, 该值会应用到其后的所有制表位。 retab-example 下例使用自动命令和 ":retab" 来编辑文件,要求保存时使用制表位 8,但编辑时将制表 位改为 4。警告: 字符串常量内部的空格也会被修改!另见 'softtabstop' 选项。 :auto BufReadPost *.xx retab! 4 :auto BufWritePre *.xx retab! 8 :auto BufWritePost *.xx retab! 4 :auto BufNewFile *.xx set ts=4

5. 复制和移动文本 copy-move

quote "{register} 指定下次的删除、抽出和放置命令 (译者注: 分别相当于剪贴 板的剪切、复制和粘贴操作) 使用寄存器 {register}。使用 大写字符寄存器时,删除和抽出操作会将内容追加到寄存器, 而非覆盖寄存器内容。特殊寄存器 "."、"%"、"#" 和 ":" 只 能用于放置命令。 :reg :registers :reg[isters] 显示所有编号寄存器和命名寄存器的类型和内容。但不显示用 作 :redir 输出目标的寄存器 (译者注: 因为本命令的输出 本身也会被重定向)。 类型可以是以下几种: "c" 用于面向字符 characterwise 文本 "l" 用于面向行 linewise 文本 "b" 用于面向列块 blockwise-visual 文本 :reg[isters] {arg} 显示 {arg} 里指定的编号寄存器和命名寄存器内容。例如: :reg 1a 会显示寄存器 '1' 和 'a'。{arg} 内可使用空格分隔。 :di :dis :display :di[splay] [arg]:registers y yank ["x]y{motion} 抽出 {motion} 覆盖的文本 [到寄存器 x]。'cpoptions' 里 包含 'E' 标志位时,如果没有任何内容可以抽出 (例如,在 第一列执行 "y0") 会报错。 yy ["x]yy 抽出 [count] 行 [到寄存器 x] linewise 行动作。 Y ["x]Y 抽出 [count] 行 [到寄存器 x] (同 yylinewise 行动 作)。如果需要 "Y" 执行抽出从光标到行尾内容的操作 (这更 合乎逻辑,但与 Vi 不兼容),可用 `:map Y y$`。 zy ["x]zy{motion} 抽出 {motion} 覆盖的文本 [到寄存器 x]。仅在选择文本列 块时和 y 有区别,见 v_zy v_y {Visual}["x]y 可视模式下,抽出高亮文本 [到寄存器 x] (关于 {Visual}, 参见 Visual-mode )。 v_Y {Visual}["x]Y 可视模式下,抽出高亮行 [到寄存器 x] (关于 {Visual},参 见 Visual-mode )。 v_zy {Visual}["x]zy 可视模式下,抽出高亮文本 [到寄存器 x]。选中列块时,不 会抽出列块每行末尾多余的空白。常与 zp 搭配使用 (关于 {Visual},参见 Visual-mode )。 :y :yank E850 :[range]y[ank] [x] 抽出 [range] 范围内的所有行 [到寄存器 x]。仅当启用 +clipboard+clipboard_provider 特性时,才可以抽 出到 "* 或 "+ 剪贴板寄存器。 :[range]y[ank] [x] {count}[range] 范围的结束行 (缺省: 当前行) 开始,抽出 {count} 行 [到寄存器 x]。参见 cmdline-ranges p put E353 E1240 ["x]p 在光标之后放置 [来自寄存器 x 的] 文本 [count] 次。 P ["x]P 在光标之前放置 [来自寄存器 x 的] 文本 [count] 次。 <MiddleMouse> ["x]<MiddleMouse> 在光标之前放置 [来自寄存器 x 的] 文本 [count] 次。省略 时默认使用 "* 寄存器。 光标会停留在新文本尾部。 仅当 'mouse' 包含 'n' 或者 'a' 时,鼠标操作才会生效。 使用滚轮鼠标时,如果经常不小心按中键粘贴了文本,可用以 下映射来关闭鼠标中键粘贴功能: :map <MiddleMouse> <Nop> :imap <MiddleMouse> <Nop> 如果还想关闭其多击版本。参见 double-click gp ["x]gp 和 p 类似,但光标会停留在新文本之后的那个位置,而非 新文本尾部。 gP ["x]gP 和 P 类似,但光标会停留在新文本之后的那个位置。 :pu :put :[line]pu[t] [x] 在第 [line] 行 (缺省: 当前行) 下方放置 [来自寄存器 x 的] 文本。总是 linewise 行动作,因而可用来将抽出的块 作为新行放置。 寄存器省略时,取决于 'clipboard' 选项: 'clipboard' 包 含 "unnamedplus" 时,会从 + 寄存器 quoteplus 粘贴, 否则当 'clipboard' 包含 "unnamed" 时,会从 * 寄存器 quotestar 粘贴,否则,从无名寄存器 quote_quote 粘 贴。 也可使用 '=' 寄存器,后跟可选表达式。表达式会继续到本 命令结束为止。如果希望 '|' 和 '"' 字符不终止本命令,需 要在其之前加上反斜杠转义。例如: :put ='path' .. \",/test\" '=' 之后如果未提供表达式,Vim 会使用上次使用的表达式。 可用 `:dis =` 察看。 :[line]pu[t]! [x] 在第 [line] 行 (缺省: 当前行) 上方放置 [来自寄存器 x 的] 文本。 :ip :iput :[line]ip[ut] [x]:put 类似,但放置后自动调整缩进,和当前行对齐。 :[line]ip[ut]! [x]:put! 类似,但放置后自动调整缩进,和当前行对齐。 ["x]]p 或 ]p ]<MiddleMouse> ["x]]<MiddleMouse>p 类似,但放置后自动调整缩进,和当前行对齐。 仅当 'mouse' 包含 'n' 或 'a' 时,鼠标操作才会生效。 ["x][P 或 [P ["x]]P 或 ]P ["x][p 或 [p [<MiddleMouse> ["x][<MiddleMouse>P 类似,但放置后自动调整缩进,和当前行对齐。 仅当 'mouse' 包含 'n' 或 'a' 时,鼠标操作才会生效。 ["x]zp 或 zp zP ["x]zP 和 pP 类似,但粘贴列块时不会补全尾部空白。因此 插入的文本不会总是矩形对齐。常与 v_zy 搭配使用。 可以使用这些命令从一处到另一处复制文本。首先用抽出、删除或者修改命令将文本存入 寄存器,然后用放置命令写入寄存器内容。也可用这些命令将文本从一个文件移动到另一 个文件,因为 Vim 在切换缓冲区时会保留所有寄存器内容 (可用 CTRL-^ 命令在文件间 快速切换)。 linewise-register characterwise-register 可用 . 重复执行放置命令 ( :put 命令除外),同时支持撤销。如果存入寄存器文本 的命令是 linewise 行动作,Vim 会在当前行下方 ("p") 或上方 ("P") 放置文本。否 则,Vim 会在光标之后 ("p") 或之前 ("P") 放置。 :put 命令总在下一行放置文本, 而 :put! 则使用上一行。 常用技巧: 命令序列 "xp" 可用于交换两个字符。而 "ddp" 可用于交换两行。"deep" 则 可用于交换两个单词 (光标应先放在首个单词之前的空白上)。 放置命令完成后, ']`] 命令可跳转到放置内容的末尾,而 '[`[ 可跳 转到放置内容的开头。 put-Visual-mode v_p v_P 在可视模式下,使用 pP 之类的放置命令时,Vim 会试图用寄存器内容覆盖选中 文本。最终效果取决于选择区域类型以及寄存器文本类型。对于列块选择,同时取决于列 块的大小、以及边界位置是否位于已有字符上 (实现细节: 实际操作是先在选择区之后放 置寄存器内容,然后再删除选中文本)。 使用 p 时,原先的选中文本会被放入无名寄存器 (可能也同步到选择区和/或剪贴 板)。便于后续将该文本放置到他处。此操作无法重复。 使用 P 时,不会改动无名寄存器 (同样也不会改动选择区或剪贴板),此操作可以重复 执行,但被删除的文本无法再被使用。如需要多次重复替换,可用 p 配合其他寄存 器。例如,先抽出要复制的文本到寄存器 "0,可视化选择要替换的文本,然后使用 "0p 。可重复任意多次,每次都会更新无名寄存器。 blockwise-put 当 (面向字符) 寄存器包含的是单行文本时,如果选中可视列块并进行放置,该文本会重 复替换所选的每一行,从而用寄存器内容的多份副本替换列块区域。示例: - 先用 yw 抽出单词 "TEXT" 到某寄存器 - 可视选择列块,如下面文本里 "v" 标识的区域 (选中头尾,按 CTRL-V ): aaavvaaa bbbvvbbb cccvvccc - 按 p ,结果是: aaaTEXTaaa bbbTEXTbbb cccTEXTccc blockwise-register 使用列块可视模式命令文本存入寄存器后,放置命令会将文本列块插入在当前行及后续 行中,光标列之前 ( P ) 或之后 ( p )。Vim 会确保整个文本列块从同一列开始。因此 插入后的效果与最初抽出或删除时保持一致。为此,Vim 可能会将部分 <Tab> 字符替换 为空格以对齐文本。不过,如果列块宽度不是 <Tab> 宽度的整数倍,并且插入位置之后 的文本包含 <Tab>,那些文本可能会出现对齐问题。 可用 zP / zp 来粘贴面向列块寄存器,这样不会在末尾附加多余的空白。 注意 在执行面向字符的抽出命令后,Vim 会将光标定位在距离缓冲区开头最近的 (首个) 抽出字符上。这意味着 yl 不会移动光标,而 yh 会将光标向左移动一个字符。 逻辑: 在 Vi 里, y 命令后跟一个反向移动作时,因为跳过屏幕重绘,光标 有时不会移动到抽出内容的首个字符。Vim 遵循 POSIX 规范,因此总 会移动光标到首个字符处。 在执行面向行的抽出命令后,光标会定位在首行,但列位置保持不变,所以光标未必会移 动到抽出内容的首个字符。 共有十种类型的寄存器: registers {register} E354 1. 无名寄存器 "" 2. 10 个编号寄存器 "0 到 "9 (译者注: 最近抽出、最近及更早跨行删除) 3. 行内删除寄存器 "- 4. 26 个命名寄存器 "a 到 "z 或 "A 到 "Z 5. 三个只读寄存器 ":、". 和 "% (译者注: 最近命令行、最近插入文本、当前文件名) 6. 轮换缓冲区寄存器 "# 7. 表达式寄存器 "= 8. 选择和拖放寄存器 "*、"+ 和 "~ (译者注: 主选择、剪切、拖放) 9. 黑洞寄存器 "_ 10. 最近搜索模式寄存器 "/ 1. 无名寄存器 "" quote_quote quotequote Vim 通过 "d"、"c"、"s"、"x" 等命令删除的内容、以及 "y" 等命令抽出的文本,都会 自动存入本寄存器,即使同时指定了其他寄存器 (如 "xdd ) 也不例外。其效果相当于 无名寄存器始终指向最近一次使用的寄存器。使用大写寄存器追加内容时,无名寄存器和 命名寄存器会保存相同的文本。'_' 寄存器是唯一例外。 "_dd 不会将删除文本存入任 何寄存器。 不指定寄存器的放置命令 ( pP ) 默认使用无名寄存器。也可显式使用 '"' 作为 名字来访问本寄存器,也就是连续输入两个双引号。写入 "" 寄存器的实际效果相当于写 入寄存器 "0。 {Vi: 切换文件时,寄存器内容会丢失,且没有 '"' 别名} 2. 编号寄存器 "0 到 "9 quote_number quote0 quote1 quote2 quote3 quote4 quote9 Vim 将抽出和删除命令的文本存入这些编号寄存器。 编号寄存器 0 存放最近抽出的文本,除非该命令用 ["x] 显式指定了其他寄存器。 编号寄存器 1 存放最近删除或修改的文本 (即使该命令指定了其他寄存器也一样)。 但删除文本少于一行时,会改用行内删除寄存器 ( quote- );以下移动命令配合删除操 作操作时是例外: %()`/?nN{} ,这些命令在 文本少于一行时,使用 "- 寄存器,但同是总是使用寄存器 1 (为了与 Vi 兼容)。注意 这些字符可能被映射 (如 matchit 插件会映射 % 字符)。 每当执行新的删除和修改时,Vim 会把上一次的寄存器 1 的内容复制到寄存器 2,2 到 3,依此类推。而寄存器 9 的原有内容会被丢弃。 {Vi: 寄存器 0 不存在} 3. 行内删除寄存器 "- quote_- quote- 本寄存器保存少于一行内容的删除文本,除非该命令用 ["x] 显式指定了其他寄存器。 4. 命名寄存器 "a 到 "z 或者 "A 到 "Z quote_alpha quotea Vim 仅在手动指定时,才使用命名寄存器。使用小写字母时,会覆盖原有内容,而使用大 写字母时,会向原有内容追加文本。'cpoptions' 里包含 '>' 标志位时,追加文本前会 自动插入一个换行符。 5. 只读寄存器 ":、". 和 "% 特殊寄存器 '%'、':' 和 '.' 只读。仅可在 pP:put 命令以及 CTRL-R (插入 和命令行模式下) 中使用。 quote_. quote. E29 ". 存放最近一次插入的文本 (和插入模式命令 CTRL-ACTRL-@ 插入的 内容一致)。注意: 本寄存器不适用于命令行上的 CTRL-R。后者的工作 方式稍有不同,例如,文本是按本义插入而不是通过放置命令 ('textwidth' 和其它选项会影响插入文本里的特殊字符,因此未必适 合在命令行上插入)。 quote_% quote% "% 存放当前文件名。 quote_: quote: E30 ": 存放最近执行过的命令行。例如: 用 "@:" 可重复执行上一条命令行命 令。 仅当手动输入至少一个字符的命令才会存入此寄存器。完全由映射触发 执行的命令,不会覆盖本寄存器内容。 {仅当编译时加入 +cmdline_hist 特性才有效} quote_# quote# 6. 轮换文件寄存器 "# 本寄存器存放当前窗口的轮换文件名。会直接影响 CTRL-^ 命令的行为。 本寄存器可写,主要用于插件修改后手动还原其原值。写入时也接受缓冲区号: let altbuf = bufnr(@#) ... let @# = altbuf 如果指定的缓冲区号不存在,会报错 E86 。 也可接受已有缓冲区名,已进行匹配: let @# = 'buffer_name' 如果有多个缓冲区匹配该名,报错 E93 ,如果没有任何缓冲区匹配该名,报错 E94 。 7. 表达式寄存器 "= quote_= quote= @= 这并不是真正用来存放文本的寄存器。而是用来在需要使用寄存器的命令中直接执行表达 式的特殊通道。表达式寄存器可读写。 " 或 CTRL-R 之后输入 '=' 时,光标会跳转到命令行,此时可输入任意表达式 (见 expression )。支持所有标准命令行编辑功能,并拥有专属的表达式历史记录。按回车 结束命令行时,Vim 会计算表达式结果。如果用 <Esc> 结束,Vim 中止表达式的计算。 如果不输入任何内容直接按回车,Vim 会使用上一次输入的表达式 (类似于 "/" 命令)。 表达式的计算结果必须能转换为字符串。数值结果会被自动转为字符串。对 p:put 命令,浮点数结果也会被自动转为字符串。列表结果中,每个列表项会转成字符 串并被单独作为一行。字典结果也被转为字符串。函数引用结果会报错 (必须手动用 string() 转换)。 "= 寄存器用于 p 命令时,计算结果字符串会在 <NL> 字符处断开。如果该字符串以 <NL> 结尾,则被视为面向行寄存器。 8. 选择和拖放寄存器 "*、"+ 和 "~ 这几个寄存器用于 GUI 界面中存放选中的文本。参见 quotestarquoteplus 。 如果剪贴板不可用或工作异常,会自动改用无名寄存器。在 Unix 上,仅当编译时加入 +xterm_clipboard 特性才能使用剪贴板。 注意 "* 和 "+ 仅在 X11 系统上有差别。二者差异可见 x11-selection 。 在 MS-Windows 上,"* 和 "+ 的完全等效,参见 gui-clipboard quote_~ quote~ <Drop> 只读寄存器 "~ 会存放最近一次拖放操作操作的文本。当有内容拖放到 Vim 内时,"~ 寄 存器会自动被填充,同时触发 <Drop> 虚拟键以作通知。用户可自定义映射该按键;缺省 行为 (全模式通用) 是在光标位置插入 "~ 寄存器的内容。 {仅当编译时加入 +dnd 特性才有效,目前只适用于 GTK GUI 版本} 注意: 仅当拖放普通文本到 Vim 时,才使用 "~ 寄存器。URI 链接列表的拖放会由程序 内部处理。 9. 黑洞寄存器 "_ quote_ 写入该特殊寄存器不会产生任何效果。可用于删除文本,而不影响任何常规寄存器。读取 本寄存器时,不返回任何内容。 10. 最近搜索模式寄存器 "/ quote_/ quote/ 本寄存器存放最近一次的搜索模式。供 n 命令和 'hlsearch' 使用。可用 :let 写 入修改。无需实际执行搜索,就能让 'hlsearch' 高亮匹配不同的内容。本寄存器无法通 过抽出或删除操作存入。搜索方向则可通过 v:searchforward 获取。 注意 从函数返回时,本寄存器值被自动复原 function-search-undo @/ 可用 :let 命令为寄存器赋值 :let-@ 。例如: :let @/ = "the" 使用放置命令而不显式指定寄存器时,Vim 会使用上次被填充内容的寄存器 (相当于无名 寄存器的内容)。如需确认将被放置的内容,可用 :dis 命令查看 (该命令会显示所有 的命名和编号寄存器;无名寄存器标记为 '"')。 以下三个命令总是用于整行。 :[range]co[py] {address} :co :copy [range] 范围内的所有行复制到 {address} 指定行的下 方。 :t :t 同 :copyVim9 脚本里不支持本命令,因为容易和变量名混淆。 :[range]m[ove] {address} :m :mo :move E134 [range] 范围内的所有行移动到 {address} 指定行的下 方。 执行移动时,会自动清除 [range] 范围内所有的文本属性。 见 text-prop-cleared

6. 文本排版 formatting

:[range]ce[nter] [width] :ce :center [range] 范围内的行和 [width] 限定的列宽内将文本居中 对齐。 [width] 缺省使用 'textwidth',为 0 时默认采用 80 列。 :[range]ri[ght] [width] :ri :right [range] 范围内的行和 [width] 限定的列宽内将文本靠右 对齐。 [width] 缺省使用 'textwidth',为 0 时默认采用 80 列。 :le :left :[range]le[ft] [indent] 左对齐 [range] 范围内的所有行。缩进量设为 [indent] (缺 省为 0)。 gq gq{motion}{motion} 动作覆盖的所有行进行排版。 排版会按以下优先级顺序选择方式: 1. 'formatexpr' 非空时,计算该表达式进行排版。每个缓冲 区可有不同的选项值。 2. 'formatprg' 非空时,调用指定的外部程序进行排版。 3. 否则,使用内置排版机制。 第三种方式 (内置排版机制) 规则如下。 'textwidth' 选项控制排版行的行宽 (见下)。该选项为 0 时,默认自动使用屏幕宽度 (但最大不超过 79 列)。 'formatoptions' 选项控制排版的方式,见 fo-table 。 排版结束后,光标会停在末行的首个非空白字符处。 注意:旧版里,"Q" 是排版命令。现在已改为启动 Ex 模式。 如果想恢复排版功能,可用以下映射: :nnoremap Q gq gqgq gqgq gqq gqq 排版当前行。带 [count] 时,排版当前行开始的相应数量的 行。 v_gq {Visual}gq 可视模式下,排版高亮文本 (关于 ({Visual},参见 Visual-mode )。 gw gw{motion}{motion} 动作覆盖的行进行排版。和 gq 类似,但排版 后光标恢复原位。而且也不考虑 'formatprg''formatexpr' 选项 (即,只使用内置排版机制)。 gwgw gwgw gww gww 使用 gw 方式排版当前行。 v_gw {Visual}gw 可视模式下,使用 gw 方式排版高亮文本 (关于 {Visual},参见 Visual-mode )。 例如: 要排版当前段落,可用: gqap gqap gq 命令执行完毕后,光标会跟随移动命令移动。这样便于 "." 重复执行连续排版。例 如, gqj (对当前行和下一行进行排版) 和 gq} (对当前行到段落尾进行排版) 都能 和此方式良好配合。注意: 设置 'formatprg' 时, gq 会把光标留在排版后的首行 (这 和过滤命令的行为一致)。 要在排版当前段落后光标恢复原位,可用: gwap 要使段落自动排版,可在 'formatoptions' 里包含 'a' 标志位。参见 auto-format'autoindent' 选项打开时,Vim 会沿用首行的缩进量,统一排版后续所有行。 排版不会影响空行 (但会影响仅有空白字符的行!)。 合并行的操作应用 'joinspaces' 选项。 可将 'formatexpr' 选项设置为表达式来实现自定义排版,也可以将 'formatprg' 选项 设置为外部排版程序。'textwidth' 和其他 Vim 选项对外部排版程序不起作用。 format-formatexpr 可将 'formatexpr' 选项设为 Vim 脚本函数,实现缓冲区的自定义排版。此功能常用于 ftplugin ,因为排版方式高度依赖于文件类型。为此,建议使用 autoload 脚本,仅 在需要时才载入对应脚本,节省性能。该脚本应命名为 <filetype>format.vim。 例如,随 Vim 官方发布提供的 $VIMRUNTIME/ftplugin 目录里的 XML 文件类型插件会将 'formatexpr' 选项设为: setlocal formatexpr=xmlformat#Format() 对应的自定义函数 xmlformat#Format() 在以下文件中定义: $VIMRUNTIME/autoload/xmlformat.vim 下方示范脚本可用于删除选中文本行尾空白。将其存放在用户 autoload 目录 (如 ~/.vim/autoload/format.vim): func! format#Format() " 仅在手动执行 gq 命令时生效 if mode() != 'n' " 其他情况下使用 Vim 内置排版机制 return 1 endif let lines = getline(v:lnum, v:lnum + v:count - 1) call map(lines, {key, val -> substitute(val, '\s\+$', '', 'g')}) call setline('.', lines) " 不使用内置排版机制! return 0 endfunc 然后,打开该自定义排版方式: setlocal formatexpr=format#Format() 注意: 插入模式下 (一般这意味着插入文本导致文本长度超出 'textwidth' 限制) ,此 函数会直接返回非零值。此时,Vim 会使用缺省的内置排版机制。 反之,使用 gq 命令排版文本时,函数会读取选中行,清除拖尾空白并在原地放存。需 要把单行拆分为多行时,小心不要覆盖任何原有内容。 在插入或替换模式下,自动排版文本时需格外留意,防止函数递归调用。可用 'debug' 选项辅助调试。 right-justify Vim 没有内置命令,实现文本的靠右控制对齐 (right justify)。可用 "par" 等外部命 令实现 (如 :.,}!par 可对当前位置到段落尾为止的文本进行排版),也可直接设置 'formatprg' 为 "par"。 format-comments 用户手册的 30.6 一节给出注释排版的总览。 Vim 可以自动对注释的插入和排版进行特殊处理。通过行首 (会忽略空白字符) 的特定字 符串 (即注释前缀),Vim 可识别注释。可以使用三种不同类型的注释: - 每行的开头都出现注释字符串。例如外壳脚本中以 "#" 开头的注释类型。 - 注释字符串仅出现在首行,后续行不出现。例如本列表使用的短横线 "-" 可被看作一 例。 - 三段式注释,包括起始字符串,结束字符串,和中间可选行的起始字符串。起始、中 间、结束字符串各不相同。例如 C 语言风格的注释: /* * this is a C comment */ 'comments' 选项是一个以逗号分隔的部分列表。每个部分定义一种类型的注释字符串 (注释前缀)。一个部分的格式是: {flags}:{string} {string} 是必须出现的字符串 (不作转义)。 {flags} 可包含以下标志位的组合: n 嵌套注释: 允许混合不同的嵌套部分。例如 'comments' 设为 "n:),n:>",则以 ">) >" 开始的行会被当作注释。 b 在 {string} 之后必须有空白字符 (包括 <Space><Tab><EOL>)。 f 仅在首行出现的注释字符串。下一行不需要注释字符串,但需要保留相同的缩进 (例如,项目符号列表 (bullet-list))。 s 三段式注释的起始字符串 m 三段式注释的中间字符串 e 三段式注释的结束字符串 l 左对齐。和 's' 或 'e' 配合使用。三段式注释的起始或结束字符串的最左侧字 符会和中间字符串的最左侧字符对齐。这是缺省值,可以省略。详情见下。 r 右对齐。同上,但对齐最右侧字符而非最左侧字符。详情见下。 O 对 "O" 命令不识别此类注释。 x 允许自动插入中间注释字符串后,通过输入结束字符串的末字符作为新行的首个 操作来结束三段式注释。详情见下。 {digits} 和 's' 或 'e' 配合使用: 为自动插入的中间或结束字符串增加 {digit} 单位 的偏移量前缀。偏移量从左对齐位置开始计算。详情见下。 -{digits}{digits} 类似,但减少缩进而非增加缩进。仅当开始或结束部分有可移除的 缩进量时才有效。 当字符串不包含 'f'、's'、'm' 或 'e' 中任何一个标志位时,Vim 假定该注释字符串在 每行开头重复出现。{flags} 字段可以为空。 在 {string} 之前或之后的任何空白字符都属于 {string} 的一部分,所以不要随便在开 头或结尾留出空白,除非这些空白的确是注释字符串的必需部分。 当某个注释字符串是另一个注释字符串的一部分时,必须将更长的字符串写在前面。例 如,要同时包含 "-" 和 "->",可用 :set comments=f:->,f:- 三段式注释必须按顺序完整给出起始、中间和结束三部分,而且中间不能间杂其他部分。 三段式 C 语言注释的示例 sr:/*,mb:*,ex:*/ 为了避免将 "*ptr" 识别为注释,中间字符串包含了 'b' 标志位。对于三段式注释,Vim 会检查起始和中间字符串之后的文本中是否包含结束字符串。如果找到,下一行将不再识 别为注释。三段式注释的中间字符串是必需的,否则 Vim 无法识别中间行。 注意上述三段式注释定义里使用的 "x" 标志位。在 C 语言注释中按回车时,Vim 会自动 为新行插入中间字符串: " * "。要结束注释,只需在新行输入其他内容前键入 "/"。这 会把中间字符串替换成结束字符串,并应用其指定的对齐方式,只保留 " */"。省却了先 按退格键再输入完整的结束字符串的麻烦。 某行同时匹配三段式注释的中间和结束部分时,如果结束部分更长,优先使用结束部分。 这使得 C 风格注释可以正常工作,无需以空格结尾的中间部分。 一个使用对齐标志位的示例,突出注释 (也很像一个 1 字)。考虑下例: :set comments=sr:/***,m:**,ex-2:******/ /*** **<--右对齐,来自 "r" 标志位 ** 2 个单位偏移量,来自 "-2" 标志位-->** ******/ 该例中,起始注释需要手动键入,然后按回车四次,最后输入 "/" 以结束注释。 以下是三段式注释的更多细节。有三个时间点会考虑对齐和偏移量相关的标志位: 在起始 注释后新开一行时、在注释未结束前新开一行时、以及自动结束三段式注释时。结束部分 的对齐标志位是反向生效的;结果是,"s" 和 "e" 使用相同对齐标志位 ("l" 和 "r") 时会使起始和结束部分拥有相同的缩进。每个注释部分只应使用一种对齐方式,但偏移量 会优先于 "r" 和 "l" 标志位。 打开 'cindent' 后,在很多情况下会覆盖对齐标志位。使用 gq= 等其他方式格 式化也不会参考对齐标志位。要定义相同行为,可使用其他的格式化选项。需要注意的 是,'cindent' 虽然有基于上下文调整注释缩进的额外选项,但无法完整复制三段式注释 的缩进对齐方式。不过,'indentexpr' 能更好地处理三段式注释。 其它示例: "b:*" 匹配 "*" 开头的行,但 "*" 后紧跟非空白字符的除外。这避免将指针 解引用操作 "*str" 被识别为注释。 "n:>" 匹配形如 ">"、">>"、">>>" 等开头的行。 "fb:-" 自动排版以 "- " 开头的项目符号列表。 本选项的缺省值为 "b:#"。这意味着 "#include" 开头的行不会被识别为注释,但以 "# define" 开头的行会。这是一种折中方案。 fo-table 'formatoptions' 选项用于控制 Vim 的内置文本排版规则。该选项是包含下列字符的字 符串。缺省值为 "tcq"。为便于阅读,选项字符间可用逗号分隔。 字符 在 'formatoptions' 里代表的含义 fo-t t 依据 'textwidth' 自动断行普通文本。 fo-c c 依据 'textwidth' 自动断行注释,并自动补全当前注释前缀。 fo-r r 插入模式下按 <Enter> 后,自动补全当前注释前缀。 fo-o o 普通模式下按 o 或者 O 新开一行时,自动补全当前注释前缀。如果在个别 位置不想要该前缀,可按 CTRL-U 快速删除。 i_CTRL-U fo-/ / 和 o 配合使用: 仅用于 // 注释前缀,仅当该前缀出现在一行开头时才会在 新行自动补全,该前缀出现在语句后方时不会。 fo-q q 允许使用 gq 排版注释。 注意 排版不会影响空白行或只包含注释前缀的行。此类行或注释前缀发生变更 的位置,会被视作新段落起点。 fo-w w 行尾空白指示当前段落会延续到下一行。而以非空白字符结尾的行会结束当前段 落。 fo-a a 对段落进行自动实时排版。新增或删除文本时,会即时重排段落。参见 auto-format 。 给出 'c' 标志位时,该设置只对能识别的注释有效。 fo-n n 排版时,识别编号列表。'formatlistpat' 选项可用于识别不同种类的列表。列 表编号之后文本的缩进量,会延续到下一行。缺省模式为数值,后跟一个可选的 '.'、':'、')'、']' 或者 '}'。 注意 此功能需要同时置位 'autoindent'。不建议与 "2" 标志位一起使用,有 兼容性问题。 示例: 1. 第一项 回绕文字 2. 第二项 fo-2 2 排版段落时,段落其余行的缩进以段落第二行的缩进量为标准,而非第一行。适 用于第一行有特殊缩进需要的段落。注意 此功能需要同时置位 'autoindent'。 示例: 段落第一行 同一段落的第二行 第三行。 注释内同样生效,这里计算缩进量时会忽略注释前缀。 fo-v v 插入模式下使用 Vi-兼容方式的自动断行: 仅在本次输入操作手动输入的空白字 符上才会断行 (注意: 这仍然不是 100% Vi 兼容。Vi 在这方面有些 "出人意料 的特性" (更准确地说是缺陷),因为它使用屏幕列而非实际列)。 fo-b b 和 'v' 类似,但仅在回绕边界及之前位置输入空白字符时才会自动断行。如果 插入前该行已超出 'textwidth' 指定的行宽,或者在到达行宽之时未输入过空 白,Vim 不会自动断行。 fo-l l 插入模式不断开长行: 插入模式开始时,如果该行已经超过 'textwidth',Vim 不会自动断行。 fo-m m 允许在取值高于 255 的多字节字符处断行。适配亚洲文本的排版,因为此时每 个字符都是可单独断开的独立单位。注意 为了遵循中日韩换行规范,标点符号 (如冒号) 后也可断行。 fo-M M 合并行时,不在多字节字符前后添加空格。优先于 'B' 标志位。 fo-B B 合并行时,两个多字节字符之间不插入空格。有 'M' 标志位时无效。 fo-1 1 避免在单字母单词后断行。只要可能,优先在该单词前断行。 fo-] ] 严格遵循 'textwidth' 限制。除非受断行禁则 (line-break-prohibition rules) 约束,否则所有行不得超出设定宽度。主要 适配中日韩文本,且需要 'encoding' 为 "utf-8" 时才生效。 fo-j j 合并多行内容时,自动删除多余注释前缀 (在合理前提下),合并为单行连续注 释。合并示例: int i; // 列表中的 // 索引 结果是: int i; // 列表中的索引 fo-p p 不在句号后的单个空白字符处断行。和 'joinspaces'cpo-J 互为补充, 配合双空格分隔句子的书写习惯。例如,假定 'textwidth' 设为 28: Surely you're joking, Mr. Feynman! 结果是: Surely you're joking, Mr. Feynman! 而不是: Surely you're joking, Mr. Feynman! 通过 't' 和 'c' 的不同组合方式可指定 Vim 何时执行自动断行: 值 行为 "" 不自动排版 (可用 gq 进行手工排版) "t" 自动排版普通文本,不排版注释 "c" 自动排版注释,不排版普通文本 (适合 C 程序) "tc" 自动排版普通文本和注释 注意 'textwidth' 为 0 时,Vim 不会执行自动排版 (但仍会根据 'comments' 选项自动 插入注释前缀)。唯一例外是包含 'a' 标志位时,见 auto-format注意 打开 'paste' 时,Vim 同样不会执行排版。 注意 即使 Vim 从不执行自动断行,也可将 'textwidth' 设为非零值,这对使用 gq 手动排版依然有用。 'comments' 选项包含 "/*"、"*" 和/或 "*/" 时,Vim 内置了一套逻辑,在处理这类注 释时会更智能。在 "/*" 或 "*/" 前后新开一行 ('formatoptions' 包含 'r' 或 'o') 时,会自动正确设置行首内容。排版或者自动断行时也会如此。在以 "/*" 或 "*" 开 头、且包含 "*/" 的行之后新开一行时,不会插入注释前缀,且新行的缩进取自注释起始 行。例如: /* ~ * 任何注释。 */ ~ 这一行的缩进和上面注释的起始行相同。 这些功能非常实用,尤其适合与 :autocmd 命令协同使用,为不同文件类型提供不同的 排版设置。 若干示例: 适用于 C 代码 (只排版注释): :set fo=croq 适用于邮件/新闻 (排版全部文本,但不通过 o 命令自动添加注释): :set fo=tcrq 自动排版 auto-format autoformat 'formatoptions' 里包含 'a' 标志位时,新增或删除文本时,会即时重排段落。非常适 合纯文本段落编辑。以下为使用要点: - 需要合理划分段落。最简单的方式是以空白行分隔段落。没有空白行时,可考虑采用 'w' 标志位,段落内除了末行外,其余行末尾都加上一个空格,以此标识段落延续。 - 可根据文件类型 filetype 设置不同的 'formatoptions'。要为单个文件单独设定, 也可用 modeline 。 - 将 'formatoptions' 设为 "aw2tq",可使文本以如下方式缩进: bla bla foobar bla bla foobar bla foobar bla bla bla foobar bla bla foobar bla bla foobar - 如果只想自动排版注释,可加上 'c' 标志位。这适合于源代码编辑场景。 - 将 'textwidth' 设置为所需宽度。此值为零时,实际使用 79 列或当前屏幕宽度两者 的较小值。 注意事项: - 如果段落划分不合理,局部编辑可能会触发所有相连的文本被自动排版。此时可考虑临 时关闭该标志位 :set fo-=a - 启用 'w' 标志位 (行尾的空格代表段落延续) 时,用 dd 删除段落末行,会导致该 段落与下一段落自动合并。 - 文本修改会被记入撤销记录。排版也属于一种文本修改,因此,排版操作也会被记入撤 销记录。这可能导致相当大的内存开销。 - 超长段落和/或复杂缩进结构的排版操作,可能会相当耗时。

7. 文本排序 sorting

Vim 提供排序函数以及排序命令。排序函数可见: sort()uniq() 。这里介绍排序命 令。 另见 :uniq :sor :sort :[range]sor[t][!] [b][f][i][l][n][o][r][u][x] [/{pattern}/] 对 [range] 范围内的所有行排序。范围省略时,为缓冲区所 有行排序。 带 [!] 则反向排序。 带 [i] 则忽略大小写。 :sort-l [l] 时使用当前 locale 的排序规则排序。 实现细节: 字符串比较基于 strcoll()。可通过 :language 参看或设置当前用作排序规则的语言。 例如: :language collate en_US.UTF-8 :%sort l 也可通过 v:collate 检查当前 locale。 按 locale 的排序通常会忽略大小写。 Mac 上此功能不能正常工作。 以下选项 [n][f][x][o][b] 互斥。 带 [n] 则按行中首个十进制数 (在 {pattern} 匹配项之后或 之内) 排序。数值包含不多于一个的前导 '-'。 带 [f] 则按行中指定的浮点数排序。浮点值通过在指定文本 (在 {pattern} 匹配项之后或之内) 上调用 str2float() 函数决定。{仅当 Vim 编译时加入浮点数支持才有效}[x] 则按行中首个十六进制数 (在 {pattern} 匹配项之后 或之内) 排序。排序不考虑引导的 "0x" 或 "0X"。数值包含 不多于一个的前导 '-'。 带 [o] 则按行中首个八进制数 (在 {pattern} 匹配项之后或 之内) 排序。 带 [b] 则按行中首个二进制数 (在 {pattern} 匹配项之后或 之内) 排序。 :sort-u :sort-uniq [u] (u 代表 unique 唯一) 则只保留重复行序列的首行 (带 [i] 时重复行的判定会忽略大小写)。 不带此标志位时,重复行序列会按其原有顺序保留。 注意 行首和行尾的空白差异会被视为不同行。 单纯想去重时,可用 :uniq 。 指定 /{pattern}/ 且不带 [r] 标志位时,会跳过匹配文本, 按匹配后的内容排序。 模式匹配考虑 'ignorecase',但忽略 'smartcase'。 可用任何非字母的字符代替斜杠作为定界符。 示例,按第二个字段 (以逗号分隔) 排序: :sort /[^,]*,/ 按虚拟第 10 列上的文本排序 (从而忽略缩进使用制表还是空 格的区别): :sort /.*\%10v/ 按每行中首个数值排序,忽略之前的内容: :sort /.\{-}\ze\d/ (说明: ".\{-}" 匹配任何文本,"\ze" 设置匹配结束位置, \d 匹配单个数位。) 带 [r] 则在匹配 {pattern} 的文本上进行排序,而不是如上 所述的按其后续文本排序。 示例,按每行前三个字母排序: :sort /\a\a\a/ r 使用 {pattern} 时,未匹配 {pattern} 的行会按其原有顺序 保留,但与有匹配 {pattern} 的行分开。使用反向排序时, 无匹配行会以反序出现,并排在已排序行之后。否则,无匹配 行会以原有顺序出现,并排在已排序行之前。 {pattern} 为空 (如 //) 时,使用最近使用的搜索模式。可 先测试好模式,再执行本命令。 注意 :sort:global 一起使用无法只对匹配行排序,这种用法基本没有意义。 除非使用 l 标志位,否则 :sort 默认不使用当前系统的 locale。不过,Vim 执行的 是 "稳定" 排序。 排序过程可以被中断,但如果中断时机太晚,最后可能会出现行重复的情况。这取决于系 统库函数的实现。

8. 文本去重 deduplicating unique

Vim 提供去重函数和去重命令。去重函数可见: uniq() 。这里介绍去重命令。 另见 :sort-uniq :uni :uniq :[range]uni[q][!] [i][l][r][u] [/{pattern}/] 删除 [range] 范围内相邻的重复行。范围省略时,处理缓冲 区所有行。 带 [i] 则比较时忽略大小写。 带 [l] 时使用当前 locale 的排序规则进行比较。 详见 :sort-l 。 带 [r] 则仅根据匹配 {pattern} 的文本进行比较,而非按其 后续文本。 带 [u] 则只保留不重复的行 (即后面没有紧跟重复内容的 行)。 带 [!] 则只保留后面紧跟重复内容的行。 如果同时给出 [!] 和 [u],[!] 优先,忽略 [u]。 指定 /{pattern}/ 且不带 [r] 标志位时,会跳过匹配文本, 按匹配后的内容进行比较。 模式匹配考虑 'ignorecase',但忽略 'smartcase'。 可用任何非字母的字符代替斜杠作为定界符。 示例,按第二个字段 (以逗号分隔) 去重: :uniq /[^,]*,/ 要忽略前 5 个字符,只保留不重复行: :uniq u /.\{5}/ {pattern} 为空 (如 //) 时,使用最近使用的搜索模式。 注意 行首和行尾的空白差异会被视为不同行。 要删除出现在任何位置的重复行 (无论是否相邻),可用 :sort-u 或外部工具。 vim:tw=78:ts=8:noet:ft=help:norl: