我有一个巨大的 csv 文件,其中有 10 个字段,用逗号分隔。不幸的是,有些行格式错误并且不包含正好 10 个逗号(当我想将文件读入 R 时会导致一些问题)。如何仅过滤掉恰好包含 10 个逗号的行?
cuo*_*glm 23
另一个POSIX:
awk -F , 'NF == 11' <file
Run Code Online (Sandbox Code Playgroud)
如果该行有 10 个逗号,则该行将有 11 个字段。所以我们简单地awk
使用,
作为字段分隔符。如果字段数为 11,则条件NF == 11
为真,awk
则执行默认操作print $0
。
使用egrep
(或grep -E
在 POSIX 中):
egrep "^([^,]*,){10}[^,]*$" file.csv
Run Code Online (Sandbox Code Playgroud)
这会过滤掉不包含 10 个逗号的任何内容:它匹配整行(^
在开头和$
结尾),恰好包含{10}
“除 ',' 之外的任意数量的字符,后跟单个 ','”序列的十次重复 ( ) ( ([^,]*,)
),然后再跟除 ',' ( [^,]*
)之外的任意数量的字符。
您还可以使用该-x
参数删除锚点:
grep -xE "([^,]*,){10}[^,]*" file.csv
Run Code Online (Sandbox Code Playgroud)
不过,这比cuonglm的awk
解决方案效率低;对于包含大约 10 个逗号的行,后者在我的系统上通常快 6 倍。更长的线路将导致巨大的减速。
最简单的grep
代码可以工作:
grep -xE '([^,]*,){10}[^,]*'
Run Code Online (Sandbox Code Playgroud)
解释:
-x
确保模式必须匹配整行,而不仅仅是其中的一部分。这很重要,因此您不会匹配超过 10 个逗号的行。
-E
表示“扩展的正则表达式”,这可以减少正则表达式中的反斜杠转义。
括号用于分组,{10}
after 表示括号内的模式行中必须正好有十个匹配项。
[^,]
是一个字符类——例如,[c-f]
将匹配 a c
、a d
、ane
或 an 的任何单个字符f
,并[^A-Z]
匹配任何不是大写字母的单个字符。所以[^,]
匹配除逗号之外的任何单个字符。
在*
之后的字符类的意思是“零个或更多的这些。”
所以正则表达式部分的([^,]*,)
意思是“除逗号之外的任何字符任意次数(包括零次),后跟一个逗号”,并{10}
指定其中的 10 个。然后[^,]*
将其余的非逗号字符匹配到行尾。
sed -ne's/,//11;t' -e's/,/&/10p' <in >out
Run Code Online (Sandbox Code Playgroud)
首先用 11 个或更多逗号分支出任何行,然后只打印那些匹配 10 个逗号的行。
显然我之前回答过这个问题......这是一个我抄袭的问题,正在寻找恰好 4 次出现的某种模式:
您可以
[num]
通过将 seds///
替换命令添加[num]
到命令中来定位模式的第 th 次出现。当您t
对成功替换进行 est 并且未指定目标:
标签时,t
est 会从脚本中分支出来。这意味着您所要做的就是测试一个s///5
或多个逗号,然后打印剩下的。或者,至少,可以处理超过最大 4 行的行。显然,您也有一个最低要求。幸运的是,这也很简单:
sed -ne 's|,||5;t' -e 's||,|4p'
Run Code Online (Sandbox Code Playgroud)
...只需将
,
一行中出现的第 4 次替换为它自己,并将您的p
rints///
附加到替换标志上。因为任何匹配,
5 次或更多次的行都已经被修剪,所以包含 4 个,
匹配项的行只包含4 个。