Vim:正则表达式删除除以给定数字列表开头的行之外的所有行

geo*_*909 3 regex vim regex-negation

我有一个 csv 文件,其中除了第一行之外的每一行都以数字开头,如下所示:

subject,parameter1,parameter2,parameter3
1,blah,blah,blah
3,blah,blah,blah
2,blah,blah,blah
44,blah,blah,blah
12,blah,blah,blah
14,blah,blah,blah
11,blah,blah,blah
10,blah,blah,blah
11,blah,blah,blah
13,blah,blah,blah
3,blah,blah,blah
...
Run Code Online (Sandbox Code Playgroud)

我想删除除第一行以外的所有行,例如以数字 1,6,12 开头的行。我正在尝试这样的事情:

:g!/^[1 6 12]\|^subject/d
Run Code Online (Sandbox Code Playgroud)

但 12 被解释为“1 或 2”,因此这也会删除以 2 开头的行。

我缺少什么,最有效的方法应该是什么?顺便说一句,我的列表包含许多多个单位数和两位数,而不是 1、6、12。

Flo*_*ris 5

字符类的[1 6 12]意思是“该类中的任何单个字符,
即其中的任何一个' ', 1, 2, 6(重复的1被忽略)。

你可以使用

:g!/^1,\|^6,\|^12,\|^subject/d
Run Code Online (Sandbox Code Playgroud)

这与您原来的语法很接近 - 但它有效(在 Mac OS X 上使用 vim 进行了测试)。

注意 - 包含逗号很重要,这样就line starting with 1不会“保护” 11,12345等。

不过,您可能想以不同的方式执行此操作 - 使用grep.

将所有“白名单”号码放入一个文件中,每行一个,如下所示:

^subject
^1,
^2,
^6,
^12,
Run Code Online (Sandbox Code Playgroud)

然后做

grep -f whitelist csvFile
Run Code Online (Sandbox Code Playgroud)

输出将是您的“编辑”文件(您可以通过管道将其传输到新文件)。

如果您对“效率”更感兴趣,您可以使您的文本文件(让我们继续称之为whitelist

subject
1
2
6
12
Run Code Online (Sandbox Code Playgroud)

并使用以下命令:

cat whitelist | xargs -I {} grep "^"{}"," cvsFile
Run Code Online (Sandbox Code Playgroud)

这需要一些解释。

xargs            - take the input one line at a time
-I {}            - and insert that line in the command that follows, at the {}
Run Code Online (Sandbox Code Playgroud)

这意味着 grep 命令将运行n一次(白名单文件中的每行一次),并且每次输入的正则表达式grep将是以下内容的串联

"^"              - start of line
{}               - contents of one line of the input file (whitelist)
","              - comma that follows the number
Run Code Online (Sandbox Code Playgroud)

所以这是一种紧凑的写作方式

grep "^subject," csvFile; grep "^1," csvFile; grep "^2," csvFile; 
Run Code Online (Sandbox Code Playgroud)

ETC。

它的优点是,您现在可以以任何您想要的方式生成白名单 - 只要它最终位于文件中,一次一行,您就可以使用它;缺点是你实际上运行了 n 次 grep 。如果您的文件变得非常大,并且白名单中有大量项目,这可能会成为一个问题;但由于您的操作系统可能会在第一次通读后将文件放入缓存中,因此速度确实相当快。锚点的使用^使正则表达式非常高效 - 一旦它找不到匹配项,它就会继续到下一行。