![헤더 스크립트와 일치하는 Perl 규칙에 "예외" 단어 추가](https://linux55.com/image/7555/%ED%97%A4%EB%8D%94%20%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%99%80%20%EC%9D%BC%EC%B9%98%ED%95%98%EB%8A%94%20Perl%20%EA%B7%9C%EC%B9%99%EC%97%90%20%22%EC%98%88%EC%99%B8%22%20%EB%8B%A8%EC%96%B4%20%EC%B6%94%EA%B0%80.png)
나는 이 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의 답변과 매우 유사하지만 줄 뒤에 루프를 추가하는 대신 foreach
s 함수 또는 해당 함수 중 하나를 split
사용하여 줄을 추가할 수 있습니다 .perl
grep
map
@titlewords = grep (!/^(and|if|the)$/i, @titlewords);
또는
@titlewords = map { /^(and|if|the)$/i ? () : $_ } @titlewords;
이러한 기능과 기능 간의 차이점에 대한 자세한 내용은 perldoc -f grep
및 을 참조하십시오. 이는 많은 스크립트 perldoc -f map
(특히)에서 일반적으로 사용되므로 시간을 들여 이들이 수행하는 작업과 작동 방식을 이해하는 것이 좋습니다.map
perl
그건 그렇고,아니요사용 #!/usr/bin/env perl
. 이러한 사용은 스크립트에서는 충분히 좋지 않지만 env
(불행히도 표준임) 스크립트에서는 완전히 손상되었으며 스크립트를 실행하는 전통적인 방법은 확실히 아닙니다.python
ruby
perl
perl
작성하려는 프로그램 유형에 따라 동작을 크게 변경할 수 있는 명령줄 옵션이 많이 있습니다. 이와 같은 것을 사용하여 env
인터프리터를 실행하면 perl
명령줄 옵션을 인터프리터에 전달하는 기능이 완전히 중단됩니다( env
지원이 없기 때문입니다. env
심지어 이 목적으로 설계되지도 않았습니다. 그렇게 하는 것은 인터프리터의 부작용을 이용하는 추악한 해킹일 뿐입니다. 실제 목적 env
- 실행하는 동안 환경 변수는 프로그램 전에 설정됩니다.
#!/usr/bin/perl
(또는 통역사에 대한 임의의 경로 )을 사용하십시오 perl
.
원하는 작업을 수행하는 또 다른 Perl 스크립트는 다음과 같습니다. 하지만 이 스크립트는 Class::CSV
and 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(...)
이런 일이 발생하지 않도록 큰따옴표를 추가하는 줄을 편집하세요.