为什么:%s / ^ $ // g不等于:g / ^ $ / d在vim中?

时间:2014-01-14 01:54:04

标签: regex vim

我想在gvim for windows中删除文件中的空白行(不是来自cygwin的vim)。

:g/^$/d   # delete all  blank lines correctly
:%s/^$//g  #can not delete all blank lines 

如何表达行尾是一个问题,
我已使用命令%!xxd详细检查了我的文件 我发现在每一行的末尾有一个 0d0a
当行尾由特殊字符$表示时,
它是否包含 0d0a
表达the end of line命令 g s 的概念是不同的?

:%s/^$\n//g   #delete all  blank lines correctly

让我感到困惑的是,^$将包含特殊字符\r\n^$命令中的s可能不包含特殊字符\r\n,但是^$命令中的g确实包含特殊字符\r\n。 哪个位置的特殊字符$指向?在\r\n之后或\r\n之前。

3 个答案:

答案 0 :(得分:7)

不,这两个命令正在做不同的事情。 :g/^$/d说“找到空行并删除它们”,而:s/^$//g表示“在此(当前)行中,将所有无行为替换为无行(仍然在同一行) ”。正如你所注意到的,后者没有意义。

编辑您的编辑:

^$不包含任何内容。字面意思是“行的开始,然后是行尾”,其中“行”由Vim检测到。 Vim知道\r\n\r\n(取决于文件及其创建的操作系统,以及Vim的选项)标记行尾,并相应地对待它。分隔符位于 ^$之间

就像你说“我家里的房间” - 这个(至少对我而言)不包括墙壁。当你说^$\n时,你说的是“空荡荡的房间,还有旁边的木墙”。 s/^$//“空了(已空)房间”; s/^$\n//“清空空荡荡的房间并打破墙壁。”

相比之下,对于g,它再次没有提及\n。它找到空行(不关心任何分隔符),然后对它执行命令;在您的情况下,命令是d:删除一行。它会删除整行(以及任何换行符)。例如,如果您编写:g/DELETEME/d,它将删除任何位于其中的DELETEME的行:它不关心匹配部分中的任何换行,它只删除匹配的行。

答案 1 :(得分:4)

d表示删除匹配的行。 s只是一种替代品。本质上,第二个表达式意味着“将^$与空字符串匹配的行替换”,但这并不会删除它们。你什么也没有替代。 ^$是零宽度断言,无法替换。

答案 2 :(得分:4)

@Amadan和@Explosion Pills都是对的,但我认为你真的需要解释“vim如何思考”你正在编辑的内容。

首先,vim基于vi,这是ex编辑器的前端。尽管vim已经走过了漫长的道路,但它仍然是一个基于行的编辑器。不要在线的末尾寻找魔法角色,因为没有! (当我说vim已经走了很长的路时,我记得添加'whichwrap'选项的时候。)

我们通常不打算区分,但硬盘上的文件与您在vim中编辑的缓冲区不同(:help buffers )。该文件是一系列字符(或字节)。当vim读取文件时,它会根据'fileformat'选项(短格式'ff')将它们分成行。由于您在Windows上工作,默认值为'ff'=dos,这意味着文件中的0d0a(a.k.a. CRLF或\r\n)用于分隔行。我有'ff'=unix,因此当我过滤0a时,我只看到xxd。 (在OS X之前,Mac使用0d,因此有三个标准!)

神奇的EOL角色根本不存在是一件好事,因为这使得vim可以在系统之间移植。作为基于行的编辑器,vim允许您执行各种操作,例如在每行上找到第一个模式匹配并对其执行某些操作。这并不总是你想要的,所以有些人习惯在每个/g命令的末尾添加:s,甚至设置'gdefault'

回到原来的问题,从缓冲区中删除一行与删除行中的所有字符非常不同。 Ex命令(记住谱系)作用于行,:d是删除行的命令。 :s命令将改变一行;不要被常见用法:%s混淆,它会在缓冲区(:s)的每一行调用:help :range