如果包含超过特定数量的非数值,则删除该行
Delete the row if it contains more than specific number of non numeric values
我有一个大的 (2GB) 逗号分隔的文本文件,其中包含一些来自传感器的数据。有时传感器关闭并且没有数据。如果每行中的 No Data
或 Off
或 any non-numeric
值超过指定数量,我想删除这些行;不包括 header。我只对从第 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
这里第一行是 header,我想保持原样。但是我想从第 3 列开始删除那些具有 2 个或超过 2 个 No Data
或 Off
或任何 columns/fields 中的任何 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 [=12=]
}' testfile.txt
这里,我只考虑No Data
和Off
。我如何计算所有 non-numeric 个字符串。如果我将 if 语句更改为
if($i ~ /[^0-9]/ ) non_numeric++
它不起作用并且没有输出。此外,由于我正在使用循环,我认为它会很慢。我们能以某种方式加快速度吗?任何命令行解决方案都可以。
惰性方式:打印 iff 字段 3-5 至少包含一个数字字符:
awk -F, ' ~ "[0-9]"' data.csv
更懒惰的方式(适用于您的样本数据):打印 iff 行包含一个逗号后跟一个数字字符:
grep ',[0-9]' data.csv
awk -F, '
{ nonnum = 0;
for (i = 3; i <= NF; i++) {
if ($i ~ /[^.0-9]/) {
nonnum++;
if(nonnum >= 2) { next; }
}
}
} 1' infile > outfile
最后的 1
如果循环从未执行过则打印该行 next
以跳过当前行的剩余模式。
使用静态字符串:
$ awk '(a=[=10=]) && gsub(/No Data|Off/,"",a)<2' file
即。将当前记录 [=13=]
复制到临时变量 a
,使用 gsub
和 print
计算 Off
和 No Data
的出现次数 if count小于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=[=12=]) && gsub(/,[^\.,0-9]+/,"",a)<3' file
它输出第一条记录(NR==1
)和少于三个非数值的记录(第三条是,Data from process value
)。
这可能对你有用 (GNU sed):
sed -r '/(.*No Data|.*Off){2}/d' file
使用交替删除具有 2 个或更多指定字符串的行。
你可以用 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
。我们用 (?<=,|^)
和 (?=,|$)
包围它;这些是与字符串的 ,
或开头(或结尾)匹配的零宽度后视和前视。这确保我们只匹配整个字段。由于我们想多次匹配一个字段,我们将所有内容都放在量化的 (...){2,}
中,我们还添加了一个 .*
来说明字段之间的内容。
通过 GNU awk,您可以使用这个好东西:
awk 'NF<2' FPAT='No Data' file
FPAT
指定一种模式,描述文本行中的字段是什么。它是一个 GNU 扩展。将其设置为静态字符串 No Data
允许我们使用 NF<2
.
简单地检查字段计数
$ 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
,即打印 header
(grep {!/\d/} @F[2..$#F]) < 2
如果第 3 列中的 non-numeric 字段数量少于两个则打印。该条件只是检查数字是否不存在
可以根据需要轻松更改要检查的列和检查次数。例如:@F[3..$#F]
从第 4 列开始检查,< 3
检查 non-numeric 字段的数量小于三个
我有一个大的 (2GB) 逗号分隔的文本文件,其中包含一些来自传感器的数据。有时传感器关闭并且没有数据。如果每行中的 No Data
或 Off
或 any non-numeric
值超过指定数量,我想删除这些行;不包括 header。我只对从第 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
这里第一行是 header,我想保持原样。但是我想从第 3 列开始删除那些具有 2 个或超过 2 个 No Data
或 Off
或任何 columns/fields 中的任何 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 [=12=]
}' testfile.txt
这里,我只考虑No Data
和Off
。我如何计算所有 non-numeric 个字符串。如果我将 if 语句更改为
if($i ~ /[^0-9]/ ) non_numeric++
它不起作用并且没有输出。此外,由于我正在使用循环,我认为它会很慢。我们能以某种方式加快速度吗?任何命令行解决方案都可以。
惰性方式:打印 iff 字段 3-5 至少包含一个数字字符:
awk -F, ' ~ "[0-9]"' data.csv
更懒惰的方式(适用于您的样本数据):打印 iff 行包含一个逗号后跟一个数字字符:
grep ',[0-9]' data.csv
awk -F, '
{ nonnum = 0;
for (i = 3; i <= NF; i++) {
if ($i ~ /[^.0-9]/) {
nonnum++;
if(nonnum >= 2) { next; }
}
}
} 1' infile > outfile
最后的 1
如果循环从未执行过则打印该行 next
以跳过当前行的剩余模式。
使用静态字符串:
$ awk '(a=[=10=]) && gsub(/No Data|Off/,"",a)<2' file
即。将当前记录 [=13=]
复制到临时变量 a
,使用 gsub
和 print
计算 Off
和 No Data
的出现次数 if count小于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=[=12=]) && gsub(/,[^\.,0-9]+/,"",a)<3' file
它输出第一条记录(NR==1
)和少于三个非数值的记录(第三条是,Data from process value
)。
这可能对你有用 (GNU sed):
sed -r '/(.*No Data|.*Off){2}/d' file
使用交替删除具有 2 个或更多指定字符串的行。
你可以用 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
。我们用 (?<=,|^)
和 (?=,|$)
包围它;这些是与字符串的 ,
或开头(或结尾)匹配的零宽度后视和前视。这确保我们只匹配整个字段。由于我们想多次匹配一个字段,我们将所有内容都放在量化的 (...){2,}
中,我们还添加了一个 .*
来说明字段之间的内容。
通过 GNU awk,您可以使用这个好东西:
awk 'NF<2' FPAT='No Data' file
FPAT
指定一种模式,描述文本行中的字段是什么。它是一个 GNU 扩展。将其设置为静态字符串 No Data
允许我们使用 NF<2
.
$ 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
,即打印 header(grep {!/\d/} @F[2..$#F]) < 2
如果第 3 列中的 non-numeric 字段数量少于两个则打印。该条件只是检查数字是否不存在
可以根据需要轻松更改要检查的列和检查次数。例如:@F[3..$#F]
从第 4 列开始检查,< 3
检查 non-numeric 字段的数量小于三个