今日主题#
- 主主题:
文本对象 - 副主题:
把编辑范围从“到哪里”升级成“改哪一块”
学习目标#
- 解决“已经会
operator + motion,但范围边界还是找得很累”的问题。 - 明确文本对象不是单纯移动,而是把“词、引号内、括号内、方括号内”当成稳定结构来操作。
- 建立最常用的对象直觉:
iw/awi"/a"i(/a(i[/a[
- 为后面的搜索替换、可视模式、代码编辑闭环做准备。
前置回顾#
- Day 003 已经建立了一个关键句式:
- operator 决定做什么
- motion 决定做到哪里
- 但真实编辑里还会遇到一个更常见的问题:
- 我不是只想“删到某处”
- 我是想“改这个词里边”
- 或者“改引号里面那段”
- 或者“删括号里的参数”
- 这时如果还只靠
w、e、$来拼范围,会逐渐觉得边界不够贴结构。 - Day 004 的作用,就是把操作范围继续从“路径”推进成“对象”。
- 当前本地环境已确认:
Vim 9.2Neovim 0.12.0
典型场景#
这一篇要解决的是真实编辑里很常见的几个高频动作:
- 改一个词,但不想自己判断该不该包含周围空格。
- 改引号里的内容,但不想把引号一起删掉。
- 删掉函数调用里的参数,但保留括号本身。
- 复制一整个带引号的字符串或一整个括号块。
如果 Day 003 解决的是“我能对一个范围做事”,那 Day 004 解决的就是“我能更自然地说出这个范围是什么”。
最小命令集#
今天只保留最高频、最适合立刻形成手感的一层。
核心前提#
- 文本对象通常只能:
- 在 Visual 模式中使用
- 或接在 operator 后面使用
词对象#
iw- inner word,词内部
aw- a word,一个词,常连同周围空白一起考虑
引号对象#
i"- 双引号内部
a"- 包含双引号本身
i'- 单引号内部
a'- 包含单引号本身
括号与方括号对象#
i(- 圆括号内部
a(- 包含圆括号本身
i[- 方括号内部
a[- 包含方括号本身
最常用组合#
ciw- 改当前词内部
daw- 删除一个词对象
ci"- 改双引号内部内容,保留引号
da"- 删除带双引号的一整个字符串
ci(- 改圆括号内部内容,保留括号
da(- 删除包含圆括号的一整个块
yi[- 复制方括号内部内容
它是怎么用的#
核心心法:文本对象不是“怎么走过去”,而是“当前这块是什么”#
Day 003 里,你更像是在说:
- 删到词尾
- 改到行尾
- 复制到某个位置
Day 004 里,你开始换一种说法:
- 改这个词
- 改这个引号里的内容
- 删这个括号块
这两者不是互相替代,而是层次不同:
- motion 更像路径
- text object 更像结构
真实编辑里,一旦目标本身是清晰结构,文本对象通常会比普通 motion 更顺手。
i 和 a 的区别:先记“内部”和“包含外壳”#
今天最重要的区分就是:
i- inner,倾向于只取内部
a- a,倾向于把对象外壳也算进去
例如:
ci"- 改双引号里面的内容,但保留
"
- 改双引号里面的内容,但保留
da"- 把带引号的整段一起删掉
ci(- 改括号里面的内容,但保留
()
- 改括号里面的内容,但保留
da(- 括号连同里面内容一起删掉
这组直觉一旦建立,后面很多对象都能类推。
iw 和 aw:先用它解决“改词”和“删词”#
词对象是今天最该先练顺的一组。
它很适合解决:
- 改变量名
- 改普通英文单词
- 删除一个多余词
最值得先形成肌肉记忆的是:
ciw- 改当前词
daw- 删除一个词对象
本地帮助里对 aw 和 iw 的区分非常明确:
aw会把前后空白一起纳入考虑iw更偏向对象内部
所以在真实效果上,经常会感觉:
ciw更适合“把词换掉”daw更适合“把这个词连带空位一起处理掉”
引号对象:最适合“保留外壳,只改内容”#
比如你有这一段:
name = "old value"如果你的真实目标是把 "old value" 改成 "new value",最自然的动作往往不是自己找边界,而是:
ci"
它的优势是:
- 不用自己判断从哪里删到哪里
- 不会误删外层引号
- 很贴合“改字符串内容”这个真实动作
而如果你是想把整个字符串,包括引号都删掉,才更像:
da"
括号对象:最适合参数、调用、数组元素这一类结构#
比如:
print(user_name, user_email)如果你只想改参数列表,保留调用壳子,通常会优先想到:
ci(
结果会变成:
print(|)然后你直接输入新参数即可。
如果你是想把整个括号块删掉,才会更像:
da(
这也是为什么文本对象一进入代码场景,价值会突然变大。
常见操作套路#
套路 1:改词,优先试 ciw#
低效做法:
- 用
w或b到词附近 - 进插入模式
- 手动删
- 重打
更稳的方式:
- 光标落在目标词内部任意位置
ciw- 直接输入新词
Esc
套路 2:改字符串内容,优先试 ci" 或 ci'#
场景非常高频:
- 改配置值
- 改 JSON / Lua / Python 里的字符串
- 改 Markdown 链接标题的一部分
如果目标是改内容不改引号,先想:
ci"ci'
套路 3:改参数列表,优先试 ci(#
场景包括:
- 改函数参数
- 改调用参数
- 改括号包住的一整段表达式
如果目标是保留括号本身,只换里面内容,先想:
ci(
套路 4:删整个对象时,再用 a#
一个很实用的判断是:
- 我是要保留壳子,还是连壳子一起处理?
通常:
- 保留结构,用
i - 连结构一起处理,用
a
例如:
- 保留引号:
ci" - 删除整段带引号文本:
da" - 保留括号:
ci( - 删除整个括号块:
da(
环境差异:vim / nvim / LazyVim#
文本对象是 Vim / Neovim 的共同底层能力#
本地 Vim 9.2 的 motion.txt 在 object-motions 章节里明确说明:
- 这组命令只能在 Visual 模式或 operator 之后使用
a系列包含对象及其相关空白或外壳i系列偏向对象内部
同样的对象说明也保留在本地 Neovim 0.12.0 的运行时文档里。
所以今天讲的不是某个插件增强,而是 Vim 系编辑器原生语法的一部分。
到了 LazyVim,文本对象会直接接到代码编辑工作流上#
LazyVim 会让你更快:
- 找文件
- 跳符号
- 看诊断
- 用 LSP
但一旦光标已经落到代码里,像下面这种动作仍然是底层主力:
- 改字符串内容
- 改函数参数
- 删一对括号里的表达式
也就是说,文本对象不是和现代工作流分离的老知识,反而是现代工作流真正落到编辑动作时最值钱的那层。
今日练习(5-10 分钟)#
练习材料#
新建一个临时文件,写入下面内容:
title = "old title"
tags = ["vim", "notes", "draft"]
call(user_name, user_email)
this sentence needs a better word练习任务#
- 用
vim或nvim打开这个文件。 - 在第一行把引号里的
old title改成new title,使用ci"。 - 在第二行复制方括号里的内容,使用
yi[。 - 在第三行把括号里的参数改成
account_id,使用ci(。 - 在第四行把
better改成clearer,优先使用ciw。 - 再额外试一次:
dawda"da(
- 每做完一步都回看自己是在操作“结构对象”,而不是手工数边界。
完成标准#
- 能清楚说出
i和a的差别。 - 能在词、引号、括号三个场景里各做出一个顺手动作。
- 能说出为什么
ci"、ci(、ciw比手工删改更贴真实场景。
今日问题与讨论#
我的问题#
问题 1:文本对象和 Day 003 的 operator + motion 是什么关系?#
- 简答:
- 文本对象可以看作一种更贴结构的范围描述方式。
- 场景:
- 你已经会写
d$、cw,但遇到“引号里面”“括号里面”这种结构时,普通 motion 不够自然。
- 你已经会写
- 依据:
- 本地
motion.txt把 text object 放在 motions 体系里,并明确说明它们可在 operator 后使用。
- 本地
- 当前结论:
- 文本对象不是替代 Day 003,而是把 Day 003 的范围表达升级成结构表达。
- 是否需要后续回看:
是
问题 2:iw 和 aw 到底先记哪个?#
- 简答:
- 两个都要记,但上手时通常先把
ciw和daw练顺。
- 两个都要记,但上手时通常先把
- 场景:
- 改一个词,和删掉一个词,往往对是否带空白的期待不同。
- 依据:
- 本地帮助里
aw包含前后空白,iw更偏向内部。
- 本地帮助里
- 当前结论:
- 改词先多想
ciw,删词时多试daw,手感会更稳定。
- 改词先多想
- 是否需要后续回看:
是
问题 3:为什么 ci" 和 da" 需要分开记?#
- 简答:
- 因为一个是在保留结构,一个是在删除整个结构。
- 场景:
- 改字符串内容时通常不想把引号破坏掉;删掉整段字符串时则可能希望连引号一起处理。
- 依据:
i/a的帮助定义就是“inner”与“a object”的差别。
- 当前结论:
- 先问自己要不要保留外壳,再决定用
i还是a。
- 先问自己要不要保留外壳,再决定用
- 是否需要后续回看:
否
外部高价值问题#
问题 1:为什么 Day 4 主线只讲词、引号、括号,没有把更多对象一起铺开?#
- 问题:
- Learn-Vim 的 text objects 看起来比这里更多,为什么主线没有一次全讲?
- 简答:
- 不是因为 Learn-Vim 没讲,而是因为主线刻意只保留最常用的一层,避免 Day 4 变成对象清单。
- 场景:
- 你今天最常碰到的是改词、改字符串、改参数列表;而句子、段落、HTML tag 对象虽然有用,但没有前面几组高频。
- 依据:
- 本地
motion.txt的 text objects 说明。 D:\program\Learn-Vim\ch04_vim_grammar.md。
- 本地
- 当前结论:
- Day 4 的主线选择是“高频优先”,不是“资料里没有所以跳过”。
- 是否需要后续回看:
是
常见误区或易混点#
- 误区 1:文本对象只是 Visual 模式技巧
- 不是。它们和 operator 组合时才最能体现价值。
- 误区 2:
i和a只是两个记法,没有本质区别- 区别很关键,一个偏内部,一个偏包含外壳。
- 误区 3:文本对象只适合代码,不适合普通文本
- 不是。
iw/aw在普通文本里同样高频。
- 不是。
- 误区 4:只要会
ciw就等于会文本对象ciw只是入口,真正的提升来自把“词、引号、括号”都当成对象。
- 误区 5:文本对象会替代普通 motion
- 不会。motion 和 text object 是互补关系。
扩展内容#
aW/iW- 按更粗粒度的
WORD工作,适合处理带符号的整段非空白文本。
- 按更粗粒度的
as/is- 句子对象,适合纯文本场景,但不是今天主线重点。
ap/ip- 段落对象,在写长文时有价值。
at/it- HTML / XML tag 对象,处理标签内容时很顺手。
a</i<- 角括号对象,和 tag 对象相关但心智略有区别。
a`/i`- 反引号对象,在 Markdown 或 shell 片段里会用到。
ab/iba(/i(的别名写法,可后续再收。
a]/i]- 今天已点到,但更复杂的嵌套与转义边界可以后续再补。
今日小结#
Day 004 最重要的变化是:
- 你不再只是对“移动路径”做操作
- 你开始对“文本结构对象”做操作
一旦这件事建立起来,很多以前要自己找边界的动作,就会自然变成:
ciwci"ci(
这正是 Vim 编辑手感开始明显上台阶的地方。
明日衔接#
下一步建议进入:
Day 005:搜索 / 替换 / 可视模式
重点会开始解决:
- 怎样更快找到目标
- 怎样批量改
- 怎样在视觉选择和结构选择之间切换
复习题#
- 为什么说文本对象是在把“范围”升级成“结构”?
i和a的核心区别是什么?ciw、ci"、ci(分别最适合什么场景?- 为什么改字符串内容时,
ci"常常比手工删改更顺? - 文本对象和普通 motion 是替代关系,还是互补关系?


