我正在查找 CSV 文件中包含该行的两个或多个字段中重复数据的所有行(即查找每个字段中没有唯一数据的所有行。)
例如,我有以下 CSV 文件:
John,Smith,Smith,21
Mary,Jones,Smith,32
John,42,42,42
Henry,Brown,Jones,31
Mary,,,21
我想要打印以下行:
John,Smith,Smith,21
John,42,42,42
打印这些行是因为这些行的一个字段中的数据出现在另一个字段中。请注意,即使“Mary,,,21”有重复的空白字段,也不会打印出来。
我可以编写一个 Python 脚本并记录每行中每个条目出现的次数,但似乎必须有更好的方法来做到这一点。
请您参考如下方法:
使用 perl :
perl -F, -lane 'my %s; print if grep { $s{$_}++ } @F'
用途:
-
-F,将字段分隔符设置为, -
-l自动处理换行 -
-a自动拆分 -
-n将其包装在while ( <> ) {中环形。 -
-e指定要执行的代码。
传入数据在 , 上自动拆分进入@F我们使用 %s散列以发现是否有骗局。
如果——根据您的评论——您需要跳过空白字段(这将被视为欺骗):
perl -F, -lane 'my %s; print if grep { /./ ? $s{$_}++ : () } @F'
这包括用于测试字段是否为空的三元运算符。
使用 Windows 进行测试(由于引号的缘故,这并不完全相同):
C:\Users\me>perl -F, -lane "my %s; print qq{line matches:$_} if grep { /./ ? $s{$_}++ : () } @F"
line matches:John,Smith,Smith,21
line matches:John,42,42,42
如果手写,它看起来更像这样:
#!/usr/bin/env perl
use strict;
use warnings;
while ( my $line = <DATA> ) {
my %seen;
chomp($line);
my @fields = split /,/, $line;
if ( grep { /./ and $seen{$_}++ } @fields ) {
print $line,"\n";
}
}
__DATA__
John,Smith,Smith,21
Mary,Jones,Smith,32
John,42,42,42
Henry,Brown,Jones,31
Mary,,,21
您可以使用 Text::CSV模块来解析它,但我建议不要这样做,除非你专门处理引用/嵌入的换行符等。
例如:
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
use Text::CSV;
my $csv = Text::CSV -> new ( {sep_char => ',', eol => "\n", binary => 1} );
while ( my $row = $csv -> getline ( \*DATA ) ) {
my %seen;
if ( grep { /./ and $seen{$_}++ } @$row ) {
print join ",", @$row, "\n";
}
}
__DATA__
John,Smith,Smith,21
Mary,Jones,Smith,32
John,42,42,42
Henry,Brown,Jones,31
Mary,,,21
