별도의 csv 파일에 있는 필드에서 3개 이상의 단어를 일치시킵니다.

별도의 csv 파일에 있는 필드에서 3개 이상의 단어를 일치시킵니다.

두 개의 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의 맨 위 행이 포함되고 그 뒤에 필드 2(제목)에 3개 이상의 일치하는 단어가 있는 csv2의 두 행이 포함됩니다. 일치하는 단어 수를 지정하는 방법은 무엇입니까?

편집: 내가 언급하는 것을 잊은 한 가지는 csv1의 행 수가 csv2의 크기보다 훨씬 작다는 것입니다(예: 수천 개에 비해 10개). 생각해 보면 가장 큰 데이터를 정의할 수 있으므로 중요하지 않은 것 같습니다. 설정은 csv1 또는 csv2입니다.

답변1

perl아마도 좀 더 쉘 중심적인 솔루션(awk?)이 있을 것입니다. 그러나 문제가 복잡해지면 저는 보통 그것을 사용합니다. 이것은 모든 것을 csv2메모리로 읽어 들여 행을 해시의 키로 수집하는 Perl 스크립트입니다. 해당 값은 해당 헤더입니다.

그런 다음 을 반복하고 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;

관련 정보