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

时间:2014-02-20 22:02:35

标签: 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
...

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

:g!/^[1 6 12]\|^subject/d

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

我错过了什么,最有效的方法是什么? 顺便说一句,而不是1,6,12,我的列表包含许多单个和2位数字。

3 个答案:

答案 0 :(得分:3)

“功能性”替代方案:

:g/./if index([1,12,6],str2nr(split(getline("."),",")[0]))<0|exec 'normal! dd'|endif

答案 1 :(得分:3)

字符类[1 6 12]表示“此类中的任何单个字符,
' ', 1, 2, 6中的任何一个(忽略重复的1)。

您可以使用

:g!/^1,\|^6,\|^12,\|^subject/d

接近原始语法 - 但它可以正常工作(在Mac OS X上使用vim进行测试)。

注意 - 包含逗号非常重要,因此line starting with 1不会“保护”1112345等。

您可能希望以不同方式执行此操作 - 使用grep

将所有“白名单”数字放在一个文件中,每行一个,如下所示:

^subject
^1,
^2,
^6,
^12,

然后做

grep -f whitelist csvFile

并且输出将是您的“已编辑”文件(您可以将其传输到新文件)。

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

subject
1
2
6
12

并使用以下命令:

cat whitelist | xargs -I {} grep "^"{}"," cvsFile

这需要一些解释。

xargs            - take the input one line at a time
-I {}            - and insert that line in the command that follows, at the {}

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

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

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

grep "^subject," csvFile; grep "^1," csvFile; grep "^2," csvFile; 

它的优势在于您现在可以按照自己的方式生成白名单 - 只要它最终存储在一个文件中,一次一行,就可以使用它;缺点是你基本上运行grep n次。如果您的文件变得非常大,并且白名单中有大量项目,那么这可能会成为一个问题;但由于您的操作系统可能会在第一次读取后将文件放入缓存中,因此它非常快。 ^锚点的使用使得正则表达式非常有效 - 只要它找不到匹配就会转到下一行。

答案 2 :(得分:2)

使用全局匹配:

:v/^\(subject\|1\|6\|12\),/ delete

对于与该正则表达式不匹配的每一行,请将其删除。

它产生:

subject,parameter1,parameter2,parameter3
1,blah,blah,blah
12,blah,blah,blah

编辑:刚才我意识到你已经在使用全局匹配了。你的错误是在角色类中。它匹配其中的任何字符而不管重复的字符,在您的情况下编号为一,二,六和一个空格。你必须像以前一样在不同的分支中分开它们。