考虑:
foo
bar
....
bar
baz
Run Code Online (Sandbox Code Playgroud)
然后:
:g/bar/s/\n/\r\r/g
Run Code Online (Sandbox Code Playgroud)
意外返回:
foo
bar
bar
bar
bar
bar
...
baz
Run Code Online (Sandbox Code Playgroud)
当我在每个bar
. 然而:
:g/bar/p
Run Code Online (Sandbox Code Playgroud)
返回:
bar
bar
...
bar
Run Code Online (Sandbox Code Playgroud)
正如预期的那样,如果所有bar
s之间都有换行符,我就会得到我所期望的——每行包含bar
. 我通过以下方式解决了这个问题:
:%s/\(bar.*\)\n/\1\r\r/g
Run Code Online (Sandbox Code Playgroud)
但我真的很想更好地了解正在发生的事情。
要了解在这个细节级别上发生了什么,我认为您必须获取源代码。因此,引用vim-7.1.314/src/ex_cmds.c
(在 的定义开头的注释ex_global()
):
这是通过两遍实现的:首先我们扫描文件中的模式,并为(不)匹配的每一行设置一个标记。其次,我们为每一行有一个标记执行命令。这是必需的,因为删除行后我们不知道在哪里搜索下一个匹配项。
因此,如果您删除:g
'ed 命令中的一行,该行的标记也会消失。如果在:g
'ed 命令中创建一行,它不会被标记,因此该命令不会在其上执行。在您的示例中,第 3 行与第 2 行连接,因此第 3 行的标记消失,第 2 行之后的下一个标记是最初放在第 4 行的标记。
此外,ex_global
设置global_busy
变量,这会导致一些命令(包括:s
)的行为略有不同。不过,我认为差异在这里无关紧要。