Сопоставление 3 или более слов из полей в отдельных CSV-файлах

Сопоставление 3 или более слов из полей в отдельных CSV-файлах

У меня есть два 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, которые имеют 3 или более совпадающих слов в поле 2 (заголовок). Как мне указать количество совпадающих слов?

EDIT: Я забыл упомянуть, что csv1 будет значительно меньше по размеру в строках, чем csv2 (как десятки по сравнению с тысячами), хотя, если подумать, это не имеет особого значения, поскольку я могу определить самый большой набор данных как csv1 или csv2.

решение1

Возможно, есть более ориентированное на оболочку решение (awk?), но я обычно обращаюсь к нему, perlкогда проблема становится настолько сложной. Вот скрипт 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;

Связанный контент