小改动

本章介绍几种修正和移动文本的方法,这包括三种修改文本的基本方法: 操作符-动作,可视模式以及文本对象。

操作符与动作

dw 命令删除一个单词。你可能认出来了, w 是词移动命令。实际上, d 命令后面可以跟任何“动作” (motion) 命令,它会删除从当前位置到光标移动到的目标位置的全部内容。

例如 4w 命令能够向后移动四个单词。所以 d4w 命令删除 4 个单词。

To err is human. To really foul up you need a computer.
                 ------------------>
                         d4w

To err is human. you need a computer.

dw 只删除从当前光标位置到目标光标位置的前一个字符。如果你用 de 命令删除字符到单词结尾,这时会删掉整个单词(包括最后一个字符):

To err is human. you need a computer.
                 ------->
                   d2e

To err is human.  a computer.

删除时是否包括光标所在的字符取决于你使用的移动命令。当不包括这个字符时,称为“非包含的”(exclusive),而包括这个字符时,称为“包含的”(inclusive)。

$ 命令移动到行尾。所以, d$ 命令从当前的位置一直删除到本行行尾。这是一个“包含的”命令,所以,这行的最后一个字符也会被删除:

To err is human. a computer.
               ------------>
                    d$

To err is human

以上定义了一个命令组合模式: 操作符-动作 。你首先输入一个操作符命令,例如, d 就是一个删除操作符。然后你输入一个动作命令,例如 4l 或者 w 。这种方法使你可以在任何你能越过的文本上执行各种操作。

修改文本

另一个操作符命令是 c ,表示修改 change。它的作用方式与 d 操作符相似,只是完成后会切换到插入模式。例如, cw 修改一个词,更精确的说:它删除一个词,并切换到插入模式。

To err is human
   ------->
     c2wbe<Esc>

To be human

这里 c2wbe<Esc> 包括如下操作:

  • c 修改操作符
  • 2w 移动两个单词的距离(与操作符组合起来,它删除两个单词并进入插入模式)
  • be 插入 be 这个单词
  • <Esc> 切换回普通模式

注解

如果留意观察会发现一个奇怪的地方: human 前面的空格没有被删除。 c 操作符在很多地方都和 d 一样,但有一个例外, cw 实际上像 ce 一样,删除到单词尾,这样单词后面的空格就不包括在内了。这要追溯到使用 Vi 的旧日子。由于很多人已经习惯了这种方式,这个不一致之处就留在 Vim 里了。

更多的修改命令

dd 可以删除一行一样, cc 修改一整行,但它会保留这一行的缩进(前导空格)。

d$ 删除到行尾; c$ 则修改到行尾。这相当于先用 d$ 删除一行再用 a 启动插入模式,以便加入新的文字。

快捷键

有些 操作符-动作 命令由于经常被使用,所以被设置为单字符命令:

  • x 表示 dl (删除当前光标下的字符)
  • X 表示 dh (删除光标左边的字符)
  • D 表示 d$ (删除到行尾)
  • C 表示 c$ (修改到行尾)
  • s 表示 cl (修改一个字符)
  • S 表示 cc (修改一整行)

在什么地方加入计数前缀

命令 3dwd3w 都是删除三个单词。如果非要寻根问底,那么: 3dw 表示删除一个单词执行 3 次,而 d3w 表示删除三个单词执行 1 次。这是一个没有分别的分别。实际上可以放两个计数前缀,例如, 3d2w 删除两个单词执行 3 次,共计六个单词。

替换单个字符

r 命令不是操作符。它只是等你输入一个字符然后用这个字符替换当前光标上的字符。可以用 cl 命令或者 s 命令完成相同的功能,但 r 命令不需要使用 <Esc> 退出插入状态:

there is somerhing grong here
rT           rt    rw

There is something wrong here


There is something wrong here
                   5rx

There is something xxxxx here

要用换行符替换一个字符可以用命令 r<Enter> 。这会删除一个字符并插入一个换行符。在这里使用计数前缀会删除多个字符但只插入一个换行符: 4r<Enter> 用一个换行符替换四个字符。

重复一个修改

. 是 Vim 中一个非常简单而有用的命令,它重复最后一次的修改操作。例如,在编辑一个 HTML 文件时,想删除所有的 <b> 标签。你把光标移到第一个 "<" 上,然后用 df> 命令删除 <b>。然后你就可以移到 </b> 的 "<" 上面用 . 命令删除它。

                     To <b>generate</b> a table of <b>contents
f<   找第一个 <       --->
df>  删除到 >            -->
f<   找下一个 <            --------->
.    重复 df>                       --->
f<   找下一个 <                        ------------->
.    重复 df >                                      -->

. 命令可以重复任何除 u (撤销), CTRL-R (重做) 和冒号命令外的修改。

可视模式

要删除一些简单的东西,用 "操作符-动作" 命令可以完成得很好。但很多情况下,并不容易确定用什么命令可以移到想修改的地方。这时候,就需要可视模式了。

可以用 v 命令启动可视模式,它会从光标位置开始选择,然后移动光标到需要选择的地方。可视模式会高亮显示选中的字符,最后执行一下 "操作符" 命令即可。

例如,要从一个单词的一半删除到下一个单词的一半:

This is an examination sample of visual mode
               ---------->
                 velllld

This is an example of visual mode

这样做的时候,不需要算向后移动多少个字符,可以在删除前清楚得看到选择了哪些字符。

如果中途改变了主意,按下 <Esc> 键就能退出可视模式。

按行选择

如果想对整行做操作,可以使用 V 命令来启动可视模式。你会发现在你作任何移动之前,整行都被高亮显示了。左右移动不会有任何效果。而通过上下移动,你可以一次选择多行。

例如,用 Vjj 可以选中三行:

           +------------------------+
           | text more text         |
        >> | more text more text    | |
选中的行 >> | text text text         | | Vjj
        >> | text more              | ↓
           | more text more         |
           +------------------------+

列块选择

如果要处理一个矩形块内的文本,可以使用 CTRL-V 启动可视模式。这在处理表格时非常有用。

name            Q1      Q2      Q3
pierre          123     455     234
john            0       90      39
steve           392     63      334

要删除中间 "Q2" 这一栏,把光标移动到 "Q2" 的 "Q" 上面。按 CTRL-V 启动列块可视模式。现在用 3j 向下移动三行,然后用 w 移到下一个单词。你可以看到最后一栏的第一个字符也被包括进来了。要去掉它,用 h 命令即可。现在按 d ,中间一栏就被删除了。

移动到另一端

如果你在可视模式下选中了一些文字,然后你又发现你需要改变被选择的文字的另一端,用 o 命令即可(o 表示 other end),光标会移动到被选中文字的另一端,现在你可以移动光标去改变选中文字的开始点了。再按 o 光标还会回到另一端。

当使用列块可视模式的时候,你会有四个角, o 只是把你移到对角上。而用 O 则能移到同一行的另一个角上。

注解

oO 在可视模式下与在普通模式下的作用有很大的不同;在普通模式下,它们的作用是在光标后或前加入新的一行。

移动文本

当你用 d x 或者其它命令删除文本的时候,这些文字会被存起来。你可以用 p 命令重新粘贴出来(p 表示 put,放置)。

看一个删除一行并粘贴的例子(相当于剪切一行然后粘贴)。首先,在要删除的行上输入 dd 删除一整行,然后移动到你要重新插入这行的地方输入 p ,这样这一行就会被插入到光标下方。

由于删除的是一整行, p 命令把该行插入到光标下方。如果删除的是一行的一部分(例如一个单词), p 命令会把它插入到光标的后面。

Some more boring try text to out commands.
                 ---->
                  dw

Some more boring text to out commands.
                 -------->
                    welp

Some more boring text to try out commands.

关于粘贴的更多知识

P 命令像 p 一样也是插入字符,但插入点在光标前面。当你用 dd 删除一行, P 会把它插入到光标所在行的前一行。而当你用 dw 删除一个单词, P 会把它插入到光标前面。

你可以执行这个命令多次,每次会插入相同的文本。

粘贴命令接受计数前缀,被插入的文本就会被粘贴指定的次数。所以 dd 后加一个 3p 会把删除行的三个拷贝插入到文本中。

交换两个字符

经常发生这样的情况,当你输入字符的时候,你的手指比脑子转得快(或者相反)。这 样的结果是你经常把 "the" 敲成 "teh"。这时,只要把光标移到 "teh" 的 "e" 上,然后执行 xp 命令即可。这个工作过程是: x 删除一个字符,保存到寄存器。 p 把这个被保存的字符插入到光标的后面,也就是在 "h" 的后面了。

teh     th     the
 x       p

拷贝文本

y 命令可以把文字拷贝到寄存器中。然后用 p 命令粘贴到别处。

由于 c 已经被用于表示 change 了,所以拷贝(copy)就不能再用 c 了。Vim 把拷贝命令称为 "yanking" 是为了更容易记住 y 这个键。

由于 y 是一个操作符,所以 yw 命令就是拷贝一个单词了。要拷贝两个单词,就可以用 y2w 。例如:

let sqr = LongVariable *
         -------------->
               y2w

let sqr = LongVariable *
                       p

let sqr = LongVariable * LongVariable

注解

yw 命令包括单词后面的空白字符。如果你不想要这个字符,改用 ye 命令。

yy 命令拷贝一整行,就像 dd 删除一整行一样。出乎意料地是, D 删除到行尾而 Y 却是拷贝一整行。要注意这个区别! y$ 拷贝到行尾。

文本对象

如果光标在一个单词的中间而又想删掉这个单词,在用 dw 删除单词前,必须先将光标移到这个单词的开始处。还有一个更简单的方法: daw

dawd 是删除操作符, aw 是一个文本对象(提示: daw 就是 "Delete A Word"(删除一个单词)。确切地说,该单词后的空格字符也被删除掉了。

使用文本对象是 Vim 中执行修改的第三种方法。上边已经有提过 "操作符-动作" 和可视模式两种方法了。现在我们又有了 "操作符-文本对象"。

这种方法与 "操作符-动作" 很相似,但它不是操作于从当前位置到移动目标间的内容,而是对光标所在位置的 "文本对象" 进行操作。文本对象是作为一个整体来处理的,光标在对象中的位置无关紧要。

还可以在可视模式下使用文本对象。这样会选中一个文本对象,而且继续留在可视模式,你可以继续多次执行文本对象命令。例如,先用 "v" 启动可视模式,再用 "as" 就可以选中一个句子。现在重复执行 "as",就会继续选中更多的句子。最后你可以使用一个操作符去处理这些被选中的句子。

文本对象的选择有多种形式,如:"aw"、"as"、"is"、"iw" 等详见文本对象。

替换模式

R 命令启动替换模式。在这个模式下,你输入的每个字符都会覆盖当前光标上的字符。这会一直持续下去,直到按下 <Esc>。

在下面的例子中,你在 "text" 的第一个 "t" 上启动替换模式:

This is text.
        Rinteresting.<Esc>

This is interesting.

你可能会注意到,这是用十二个字符替换一行中的五个字符。如果超出行的范围, R 命令自动进行行扩展,而不是替换到下一行。

你可以通过 <Insert> 在插入模式和替换模式间切换。

但当你使用 <BS> (退格键) 进行修正时,你会发现原来被替换的字符又回来了。这就好像一个 "撤销" 命令一样。

一些常用的修改命令

  • ~ 修改光标下字符的大小写,并移动到下一个字符。这不是一个操作符(除非设置了 'tildeop'),所以你不能连接一个动作命令。这个命令在可视模式下也有效,它会改变被选中的所有文本的大小写。
  • I 移到当前行的第一个非空字符并启动插入模式。
  • A 移动到行尾并启动插入模式。
  • "*yy 拷贝一行到系统剪贴板中
  • "*p 粘贴系统剪贴板中的内容