我有一个大的(2GB)逗号分隔文本文件,其中包含来自传感器的一些数据。有时传感器关闭,没有数据。如果每行中有超过指定数量的No Data
或Off
或any non-numeric
值,我想删除行;不包括标题。我只对从第3栏开始算起来感兴趣。例如:我的数据如下:
Tag, Description,2015/01/01,2015/01/01 00:01:00,2015/01/01 00:02:00, 2015/01/01 00:02:00
1827XYZR/KB.SAT,Data from Process Value,2.1,Off,2.7
1871XYZR/KB.RAT,Data from process value,Off,No Data, No Data
1962XYMK/KB.GAT,Data from Process Value,No Data,5,3
1867XYST/KB.FAT,Data from process value,1.05,5.87,7.80
1871XKZR/KB.VAT,Data from process value,No Data,Off,2
这里的第一行是标题,我希望保持原样。但我希望从第3列开始删除任何列/字段中包含2个或2个以上No Data
或Off
或任何non numeric
字段的行。换句话说,行中有4个或五个文本字段。在该示例中,第3行和第6行有2个或多于2个No Data
或Off
字段,我想删除它们。因此,我的首选输出是
Tag, Description,2015/01/01,2015/01/01 00:01:00,2015/01/01 00:02:00, 2015/01/01 00:02:00
1827XYZR/KB.SAT,Data from Process Value,2.1,Off,2.7
1962XYMK/KB.GAT,Data from Process Value,No Data,5,3
1867XYST/KB.FAT,Data from process value,1.05,5.87,7.80
我可以针对特定情况使用循环执行此操作:
awk -F, '{ non_numeric=0;
for(i=1;i<=NF;i++){
if($i ~ // ) non_numeric++
}
if(non_numeric<2) print $0
}' testfile.txt
在此,我只考虑No Data
和Off
。如何计算所有非数字字符串。如果我将if语句更改为
if($i ~ /[^0-9]/ ) non_numeric++
它不起作用并且没有输出。此外,因为我使用循环,我认为它会变慢。我们能以某种方式加快速度吗?任何Commandline解决方案都可以。
答案 0 :(得分:2)
awk -F, '
{ nonnum = 0;
for (i = 3; i <= NF; i++) {
if ($i ~ /[^.0-9]/) {
nonnum++;
if(nonnum >= 2) { next; }
}
}
} 1' infile > outfile
如果循环从未执行1
以跳过当前行的剩余模式,则末尾的next
将打印该行。
答案 1 :(得分:1)
使用静态字符串:
$ awk '(a=$0) && gsub(/No Data|Off/,"",a)<2' file
IE中。将当前记录$0
复制到临时变量a
,如果计数,则使用Off
和No Data
计算gsub
和print
的出现次数小于2.输出:
Tag, Description,2015/01/01,2015/01/01 00:01:00,2015/01/01 00:02:00, 2015/01/01 00:02:00
1827XYZR/KB.SAT,Data from Process Value,2.1,Off,2.7
1962XYMK/KB.GAT,Data from Process Value,No Data,5,3
1867XYST/KB.FAT,Data from process value,1.05,5.87,7.80
如果要匹配所有非数字字符串,请使用:
awk 'NR==1 || (a=$0) && gsub(/,[^\.,0-9]+/,"",a)<3' file
它输出第一个记录(NR==1
)和少于三个非数字值的记录(第三个是,Data from process value
)。
答案 2 :(得分:1)
您可以使用grep
执行此操作:
grep -vP '((?<=,|^)(No Data|Off)(?=,|$).*){2,}' input
Tag, Description,2015/01/01,2015/01/01 00:01:00,2015/01/01 00:02:00, 2015/01/01 00:02:00
1827XYZR/KB.SAT,Data from Process Value,2.1,Off,2.7
1962XYMK/KB.GAT,Data from Process Value,No Data,5,3
1867XYST/KB.FAT,Data from process value,1.05,5.87,7.80
说明:(No Data|Off)
与No Data
或Off
匹配。我们通过(?<=,|^)
和(?=,|$)
将其包围起来;这些是零宽度的lookbehind和lookahead,与字符串的,
或开头(或结尾)匹配。这可确保我们仅与整个字段匹配。由于我们希望多次匹配某个字段,因此我们将所有内容都放在量化的(...){2,}
内,并添加.*
来说明字段之间的内容。
答案 3 :(得分:1)
使用GNU awk,你可以使用这个好东西:
awk 'NF<2' FPAT='No Data' file
FPAT
指定一种模式,用于描述文本行中的字段。它是GNU扩展。将其设置为静态字符串No Data
,我们只需使用NF<2
检查字段数。
答案 4 :(得分:1)
$ perl -F, -ane 'print if $. == 1 || (grep {!/\d/} @F[2..$#F]) < 2' ip.txt
Tag, Description,2015/01/01,2015/01/01 00:01:00,2015/01/01 00:02:00, 2015/01/01 00:02:00
1827XYZR/KB.SAT,Data from Process Value,2.1,Off,2.7
1962XYMK/KB.GAT,Data from Process Value,No Data,5,3
1867XYST/KB.FAT,Data from process value,1.05,5.87,7.80
-F,
在,
$. == 1
如果行号为1
,即打印标题(grep {!/\d/} @F[2..$#F]) < 2
打印。条件只是检查数字是否不存在可以根据需要轻松更改要检查的列和检查次数。例如:@F[3..$#F]
检查第4列以后,< 3
检查少于3的非数字字段数
答案 5 :(得分:0)
懒惰方式:打印iff字段3-5包含至少一个数字字符:
awk -F, '$3$4$5 ~ "[0-9]"' data.csv
lazier方式(适用于您的示例数据):print iff row包含逗号后跟数字字符:
grep ',[0-9]' data.csv
答案 6 :(得分:0)
这可能适合你(GNU sed):
sed -r '/(.*No Data|.*Off){2}/d' file
使用交替删除包含2个或更多指定字符串的行。