vim 入坑指南(三)— motion 进阶

上一篇里,我们提到移动光标是其他几个操作(输入、删除、替换)的发起者,文本处理的效率取决于光标移动的速度和准度。之后简单的解释了 motion 和 operator,并且提供了两个公式:
1
2
公式一:[数字] + operator + motion
公式二:operator + [数字] + operator (前后均为同一个 operator)

不过都太抽象了,这一篇会介绍更多的 motion,提供更多的例子。

行内单字符查找

f (find) 和 t (till) 的功能都是在行内 向右 做单字符查找,并移动光标,只不过 f 是把光标挪到字符上, t 则是把光标挪到字符的左边 (till 的意思)。如果想要 向左 做查找,使用 FT 便好了。直接看例子,假设光标在 set relativenumber 行首,我可以通过 f 键把光标

  • 移至第一个 r 处:fr
  • 移至第二个 r 处:2fr
  • 移至第三个 e 处:3fe

但是,如果我使用的是 t 的话:

  • 移至第一个 r 的左边:tr
  • 移至第二个 r 的左边:2tr
  • 移至第三个 e 的左边:3te

大范围移动

如果我们需要大范围的移动光标,我们可以采用一下这几个 motion :

  • 在窗口内:
    • H (Home) 移光标至窗口第一行
    • M (Middle) 移光标至窗口中间一行
    • L (Last) 移光标至窗口最后一行
  • 在文件范围内:
    • gg 移光标至文件第一行
    • G 移光标至文件最后一行

大伙也可以试试在它们之前加上数字,比如 2gg, 5H, 3L,看看有什么效果。

motion 总结

我们把所有提到过的 motion 做个分类(演示图都可以在 关键词 中看到):

  • words motions
    • w 移光标至下一词
    • b 移光标至上一词
    • e 移光标至词末
  • Left-right motion
    • h 光标向左移一字节
    • l 光标向右移一字节
    • $ 移光标至行末
    • 0 移光标至行首
    • ^ 移光标至本行首个非空格的字节
  • Up-down motions
    • j 光标向下移一行
    • k 光标向上移一行
    • gg 移光标至整个文本的首行首个非空格字节
    • G 移光标至整个文本最后一行首个非空格字节
  • Other motions
    • % 移光标至匹配括号的另一端
    • H 移光标至窗口第一行
    • M 移光标至窗口中间一行
    • L 移光标至窗口最后一行

实例操作

下面,我们通过几个实例来看看如何运用开头的两个公式

例子1:把 set relativenumber 变成 set number

假设光标在 relativenumber 词首,我们可以:

  1. 替换整个词,按 cw (change word) 进入输入模式
  2. 删除 relative ,按 d2fe (delete find 2 e)
  3. 删除 relative ,按 dtn (delete till n)

例子2:把 World 变成 Vim

假设光标在行首,我们可以:

  1. 4w (move 4 words) 移动光标,然后按 cw 进入输入模式
  2. fW (find W) 移动光标,然后按 cw 进入输入模式

例子3:把 Hello World! 变成 Hello World!!!

除了用 i 可进入输入模式之外,也可以用 a (append)。a 会在 i 的右侧一字节进入输入模式(所谓 append 的意思)。假设光标在行首:

  1. f! (find !) 移动光标,然后按 a 进入输入模式
  2. $ (end of line) 移动光标,然后按 i 进入输入模式

例子4:把 Hello World! 变成 Vimpress

假设光标在 Hello 词首,我们可以:

  1. cf! (change find !) 后进入输入模式
  2. ci" (change inner “) 后进入输入模式

等等,这个 i" 是个什么鬼?还记得曾经有个叫 文本对象 的东西么?就是这个。

文本对象 (text-object)

文本对象 是 vim 描述文本的一种方式, 只能放在 operator 之后,由 i (inner) 或 a (a) 加 文本范围 (下面会有表格) 组成。其中, i 表示 “在文本范围之内”, a 表示 “整个文本范围”。

文本范围 代表
w word 词
s sentence 句
p paragraph 段
t tag (HTML 或 XML)标签
[ 或 ] […]
( 或 ) (…)
< 或 > <…>
{ 或 } {…}
“…”
‘…’
` `…`

举个例子 di" (delete inner “) 会删除双引号之内的所有内容,而 da" (delete a “) 则会删除包含双引号在内的所有内容。以此类推,其他几个文本本范围都是一样的道理。举个例子,假设光标处在 contains 词首:

  • di(di) 会删除 contains 这个词
  • da(da) 会删除 contains 以及括号
  • di' 会删除单引号之内这个词
  • da' 会删除包括单引号之内的所有内容
  • di[di] 也是同样的道理
  • da[da]

文本对象说起来抽象,实际操作几次就能掌握了,熟练掌握能大大提高我们的效率。之后我们会常常用到的。

好啦,这一篇就先说这么说。下一篇咱们依旧说不到 插件,因为还缺少几个简单的操作,才能构成文本处理的基本流程 (workflow)。在有了完整的处理流程后,再来说说如何在 vim 中做到 DRY (don’t repeat yourself)。

VZJ wechat
欢迎您扫一扫上面的二维码,订阅 V 字君的微信公众号。