我有一个巨大的csv文件,其中10个字段用逗号分隔。不幸的是,某些行格式错误,并且不完全包含10个逗号(当我想将文件读入R时,这会引起一些问题)。如何仅过滤出恰好包含10个逗号的行?
grep答案没有一个可以接受的答案……
我有一个巨大的csv文件,其中10个字段用逗号分隔。不幸的是,某些行格式错误,并且不完全包含10个逗号(当我想将文件读入R时,这会引起一些问题)。如何仅过滤出恰好包含10个逗号的行?
grep答案没有一个可以接受的答案……
Answers:
另一个POSIX:
awk -F , 'NF == 11' <file
如果该行有10个逗号,则该行中将有11个字段。因此,我们只需让awk使用,作为字段分隔符。如果字段数为11,则条件NF == 11为true,awk然后执行默认操作print $0。
-F设置字段分隔符并NF引用给定行中的字段数。由于没有代码块{statement}附加到该条件NF == 11,因此默认操作是打印该行。(@cuonglm,如果愿意,可以随时添加此说明。)
awk -F , 'NF != 11' <file
-或开头的文件-。
使用egrep(或grep -E在POSIX中):
egrep "^([^,]*,){10}[^,]*$" file.csv
这会过滤掉不包含10个逗号的所有内容:它匹配整行(^在开头和$结尾),完全包含{10}序列“除','以外的任何数量的字符,后跟单个','”的十个重复()。 (([^,]*,)),然后再加上除“,”([^,]*)以外的任意数量的字符。
您还可以使用-x参数来删除锚点:
grep -xE "([^,]*,){10}[^,]*" file.csv
但是,这比cuonglm的awk解决方案效率低。对于大约10个逗号的行,后者在我的系统上通常快六倍。更长的线会导致巨大的减速。
最有效的grep代码:
grep -xE '([^,]*,){10}[^,]*'
说明:
-x确保模式必须与整行匹配,而不仅仅是部分匹配。这很重要,因此您不要匹配超过10个逗号的行。
-E 表示“扩展的正则表达式”,这可以减少正则表达式中的反斜杠转义。
括号用于分组,{10}其后意味着括号中的模式行中必须恰好有十个匹配项。
[^,]是一个字符类,例如,[c-f]将与c,a d,an e或an的任何单个字符匹配f,并且[^A-Z]将与非大写字母的任何单个字符匹配。因此[^,]匹配除逗号以外的任何单个字符。
*字符类的after表示“其中零个或多个”。
因此,正则表达式部分的([^,]*,)意思是“除逗号以外的任何字符任何次数(包括零次),后跟一个逗号”,并{10}指定其中的10个。然后[^,]*将其余的非逗号字符匹配到该行的末尾。
sed -ne's/,//11;t' -e's/,/&/10p' <in >out
首先,用11个或更多逗号分隔出任何行,然后打印仅匹配10个逗号的行。
显然,我之前已经回答了这个问题……这是我的一个抄袭问题,该问题恰好出现了某种模式的4次出现:
您可以
[num]通过将seds///ubstitution命令添加[num]到命令中来确定模式的出现。当您t估算成功替换并且不指定目标:标签时,test分支出脚本。这意味着您需要做的就是测试一个s///5或多个逗号,然后打印剩余的内容。或者,至少,它可以处理超过您的最大值4的行。显然,您也有最低要求。幸运的是,这很简单:
sed -ne 's|,||5;t' -e 's||,|4p'
...只需
,用自身替换一行中的第4次出现,然后p将s///lint标记在ubstitution标志上。因为匹配,5次或更多次的任何行都已被修剪,所以包含4个,匹配项的行仅包含4个。
s/hello/world/2为s//world/2,那么GNU sed可以正常工作。sed从祖传/usr/5bin/posix/sed遗物中拿出两个,加高segfault,/usr/5bin/sed进入不定式循环。
sed和的讨论awk(在注释中)—我喜欢并赞成此答案,但请注意,接受的awk答案的翻译为:“打印11行的行”,而该sed答案的翻译为:“尝试删除第11个逗号;如果失败,请跳至下一行。尝试用其自身替换第10个逗号;如果成功,请打印行。” 的awk回答给人以计算机指令只是你会表达他们在英语的方式。(awk适用于基于字段的数据。)
这是一种Perl方式:
perl -F, -ane 'print if $#F==10'
将-n导致perl按行读入其输入文件中的行并执行给定的脚本-e,每行。在-a自动分割轮流:每个输入线将在由给定的值进行分割-F(在此为逗号)并保存为阵列@F。
的$#F(或者更一般地$#array),是阵列的最高索引@F。因为数组在开始0,与11个字段的线将具有@F的10。因此,如果脚本恰好具有11个字段,则它将打印该行。
print if @F==11在标量上下文中作为数组返回元素数。
如果字段可以包含逗号或换行符,则您的代码需要了解 csv。示例(三列):
$ cat filter.csv
a,b,c
d,"e,f",g
1,2,3,4
one,two,"three
...continued"
$ cat filter.csv | python3 -c 'import sys, csv
> csv.writer(sys.stdout).writerows(
> row for row in csv.reader(sys.stdin) if len(row) == 3)
> '
a,b,c
d,"e,f",g
one,two,"three
...continued"
我想到目前为止,大多数解决方案都将丢弃第二行和第四行。
sed这里所做的一样)扫描比寻找的匹配项还要远的匹配项,尽管此问题可以。您不应该关闭此窗口。