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

3

我有一个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。

3个回答

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

可以使用

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

这段话的翻译如下:

这种方法接近于您原来的语法,但它可以工作(在Mac OS X上使用vim测试过)。

请注意 - 包括逗号非常重要,这样以数字1开头的行就不会“保护”11、12345等数字。

您可能希望使用grep进行不同的操作。

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

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

那么做。
grep -f whitelist csvFile

“并且输出将是您“编辑”后的文件(您可以将其导入到新文件中)。如果您对“效率”更感兴趣,您可以将文本文件(让我们继续称之为白名单)简化为”
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; 

等等。

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


希望我能为grep技巧点赞,但是我的声望不够。 - geo909
@geo909 - 我很高兴接受你的赞美,而不是点赞! - Floris

3

使用全局匹配:

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

对于不符合该正则表达式的每一行,都要删除它。

结果如下:

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

编辑:刚刚我意识到你已经在使用全局匹配。你的错误在于字符类。它匹配类内任何重复的字符,例如数字1、2、6和一个空格。你必须将它们分成不同的分支,就像我之前做的那样。


1
顺便提一下,:v:g!的同义词。 - benjifisher

3
一种“功能性”的替代方案:
:g/./if index([1,12,6],str2nr(split(getline("."),",")[0]))<0|exec 'normal! dd'|endif

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接