我有两个 csv 文件:
这是 csv1:
11, The Sun Still Shines in Reading, 64312, 464566
13, You and Me Together Again London, 564564, 131355
12, What's the Story Now Your Gone, 4545646, 1124545
17, Hello I love you, 456899, 1259898
这是 csv2:
69, The Sun Shines, 6464, 52364
12, Tell me your name, 56456, 21345
17, From London to New York, 897944, 234655
97, Reading Still Shines, 545464, 16748967
我有这段代码,它允许匹配标题(位于字段 2 中)。
cat $csv1 |cut -d, -f2 | while read p; do
grep -i "$p" $csv2
if [ $? -eq 0 ];then
grep -i "$p" $csv1
fi
done
目前,此代码查看 csv1 中的每一行,如果 csv2 中存在具有匹配标题的行,则会将匹配的行一起打印。这真的很有效。
但是,我现在想调整脚本,以便它检查是否有 3 个或更多单词匹配,而不是搜索确切的标题。
因此,此页面上的 csv 数据的输出将是:
11, The Sun Still Shines in Reading, 64312, 464566
69, The Sun Shines, 6464, 52364
97, Reading Still Shines, 545464, 16748967
其中包含顶部 csv1 中的行,后跟 csv2 中的两行,它们在字段 2(标题)中具有 3 个或更多匹配单词。如何指定匹配单词的数量?
编辑:我忘记提到的一件事是,csv1 的行数比 csv2 的大小要小得多(就像 10 与数千相比),尽管考虑一下,我想这并不重要,因为我可以定义最大的数据设置为 csv1 或 csv2。
答案1
perl
可能有一个更以 shell 为中心的解决方案(awk?),但当问题变得如此复杂时我通常会转向。这是一个 perl 脚本,它将所有内容读csv2
入内存,将行作为键收集到散列中,其值是相应的标题。
然后循环遍历csv1
,取出标题,然后对于 中的每个标题csv2
,计算标题中每个单词出现的次数。如果大于desired
,则打印匹配的标题及其来自 的“源”行csv1
。
#!/usr/bin/env perl
my @csv2 = ();
open CSV2, "<csv2" or die;
@csv2=<CSV2>;
close CSV2;
my %csv2hash = ();
for (@csv2) {
chomp;
my ($title) = $_ =~ /^.+?,\s*([^,]+?),/; #/ match the title
$csv2hash{$_} = $title;
}
open CSV1, "<csv1" or die;
while (<CSV1>) {
chomp;
my ($title) = $_ =~ /^.+?,\s*([^,]+?),/; #/ match the title
my @titlewords = split /\s+/, $title; #/ get words
my $desired = 3;
my $matched = 0;
foreach my $csv2 (keys %csv2hash) {
my $count = 0;
my $value = $csv2hash{$csv2};
foreach my $word (@titlewords) {
++$count if $value =~ /\b$word\b/i;
last if $count >= $desired;
}
if ($count >= $desired) {
print "$csv2\n";
++$matched;
}
}
print "$_\n" if $matched;
}
close CSV1;