헤더 스크립트와 일치하는 Perl 규칙에 "예외" 단어 추가

헤더 스크립트와 일치하는 Perl 규칙에 "예외" 단어 추가

나는 이 Perl 스크립트(Jeff Schaller 덕분에)를 사용하여 다음과 같이 두 개의 별도 csv 파일의 제목 필드에 있는 3개 이상의 단어를 일치시켜 왔습니다.

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

스크립트는 다음과 같습니다

#!/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;

제목 사이의 특정 단어를 무시하고 일치 단어로 분류하지 않으려는 것을 그때 깨달았습니다. 비교하기 전에 sed를 사용하여 csv 파일을 삭제했지만 프로세스에서 데이터가 손실되므로 이상적이지 않습니다. 이 Perl 스크립트에 예외로 간주되는 단어를 어떻게 추가합니까? 예를 들어, 스크립트가 제목을 일치시킬 때 세 개의 개별 단어를 무시하여 규칙의 예외가 되도록 하려고 and if한다고 가정해 보겠습니다 .the

답변1

여행 후

my @titlewords = split /\s+/, $title;    #/ get words

배열에서 단어를 제거하는 코드를 추가합니다.

my @new;
foreach my $t (@titlewords){
    push(@new, $t) if $t !~ /^(and|if|the)$/i;
}
@titlewords = @new;

답변2

이것은 @meuh의 답변과 매우 유사하지만 줄 뒤에 루프를 추가하는 대신 foreachs 함수 또는 해당 함수 중 하나를 split사용하여 줄을 추가할 수 있습니다 .perlgrepmap

@titlewords = grep (!/^(and|if|the)$/i, @titlewords);

또는

@titlewords = map { /^(and|if|the)$/i ? () : $_ } @titlewords;

이러한 기능과 기능 간의 차이점에 대한 자세한 내용은 perldoc -f grep및 을 참조하십시오. 이는 많은 스크립트 perldoc -f map(특히)에서 일반적으로 사용되므로 시간을 들여 이들이 수행하는 작업과 작동 방식을 이해하는 것이 좋습니다.mapperl


그건 그렇고,아니요사용 #!/usr/bin/env perl. 이러한 사용은 스크립트에서는 충분히 좋지 않지만 env(불행히도 표준임) 스크립트에서는 완전히 손상되었으며 스크립트를 실행하는 전통적인 방법은 확실히 아닙니다.pythonrubyperl

perl작성하려는 프로그램 유형에 따라 동작을 크게 변경할 수 있는 명령줄 옵션이 많이 있습니다. 이와 같은 것을 사용하여 env인터프리터를 실행하면 perl명령줄 옵션을 인터프리터에 전달하는 기능이 완전히 중단됩니다( env지원이 없기 때문입니다. env심지어 이 목적으로 설계되지도 않았습니다. 그렇게 하는 것은 인터프리터의 부작용을 이용하는 추악한 해킹일 뿐입니다. 실제 목적 env- 실행하는 동안 환경 변수는 프로그램 전에 설정됩니다.

#!/usr/bin/perl(또는 통역사에 대한 임의의 경로 )을 사용하십시오 perl.


원하는 작업을 수행하는 또 다른 Perl 스크립트는 다음과 같습니다. 하지만 이 스크립트는 Class::CSVand List::Compare모듈과 두 개의 배열 해시를 사용하여 CSV 파일을 비교합니다.

#! /usr/bin/perl

use strict;
use warnings;

use Class::CSV;
use List::Compare;

sub parse_csv($%) {
  my($filename,$tw) = @_;

  # exclude the following word list and the "empty word"
  my @exceptions = qw(and if the);
  my $exceptions = '^(\s*|' . join('|',@exceptions) . ')$';


  my $csv = Class::CSV->parse(
      filename => $filename,
      fields   => [qw/id title num1 num2/]
  );

  # build a hash-of-arrays (HoA), keyed by the CSV line. Each array
  # contains the individual words from each title for that line (except
  # for those matching $exceptions).  The words are all converted to
  # lowercase to enable case-insensitive matches.
  foreach my $line (@{$csv->lines()}) {

    # The following three lines are required because the input file has
    # fields separated by ', ' rather than just ',' which makes
    # Class::CSV interpret the numeric fields as strings.
    # It's easier/quicker to do this than to rewrite using Text::CSV.
    #
    # The final output will be properly-formed CSV, with only a comma as
    # field separator and quotes around the title string.
    my $key = join(',',$line->id,'"'.$line->title.'"',$line->num1,$line->num2);
    $key =~ s/([",])\s+/$1/g;   # trim whitespace immediately following " or ,
    $key =~ s/\s+([",])/$1/g;   # trim whitespace immediately preceding " or ,

    # If it wasn't for the not-quite-right CSV format, we could just use:
    #my $key = $line->string;

    push @{ $tw->{$key} }, grep (!/$exceptions/oi, split(/\s+/,$line->title));
  };
};

# two hashes to hold the titlewords HoAs
my %tw1=();
my %tw2=();

parse_csv('csv1',\%tw1);
parse_csv('csv2',\%tw2);

# now compare the HoAs
foreach my $k2 (sort keys %tw2) {
  my @matches = ();
  foreach my $k1 (sort keys %tw1) {
    my $lc = List::Compare->new('-u', \@{ $tw2{$k2} }, \@{ $tw1{$k1} });
    push @matches, $k1 if ($lc->get_intersection ge 3);
  };
  print join("\n",sort(@matches,$k2)),"\n\n" if (@matches);
};

산출:

11,"The Sun Still Shines in Reading",64312,464566
97,"Reading Still Shines",545464,16748967

각 일치 항목 집합은 정렬되며 예제 출력에는 표시되지 않더라도(일치 항목 집합이 하나만 있기 때문에) 각 집합은 별도의 단락으로 인쇄됩니다(예: 빈 줄로 구분)

그런데, 제목 필드 주위에 큰따옴표를 원하지 않으면 my $key=join(...)이런 일이 발생하지 않도록 큰따옴표를 추가하는 줄을 편집하세요.

관련 정보