使用简单的模式匹配来比较文件线



我有两个文件:在第一个文件中,每行都有与之关联的一些标签;第二个文件包含属于某些类别的标签。

file1 - 标签行:

I have never had an issue.  L_102 ----- L_127
I travel overseas and offer a lot of services that are very useful to me    L_105 ----- L_134 ----- L_148
Expense to have L_522
Great benefits  L_148
prestige    L_118

file2 - 标签下落的类别:

Issues:113,114,115,116,127
Benefits:105,220,154,543,590
General:148,134,154

我写了一个perl脚本来从第一个文件中获取标签。

#!/usr/bin/perl
use strict;
use warnings;
my $file = shift || "INPUTFILE";
my $outputfile = shift || "OUTPUTFILE";
open my $fh, '<', $file or die "Can not open '$file': $!";
open( OUTFILE, ">", $outputfile) or die "Can not open '$outputfile': $!";
while(my $w = <$fh>) {
    my @matches = $w =~ m/(L_[0-9][0-9][0-9])/g;
    for(@matches){s/L_//g;
    s/s+/t/g;
    }
    print OUTFILE "@matchesn";
}

第一个脚本的输出是:

102 127
105 134 148
522
148
118

我有第二个perl脚本可以从第二个文件中获取级别(其中包含类别):

#!/usr/bin/perl
use strict;
use warnings;
my $file = shift || "INPUTFILE";
my $outputfile = shift || "OUTPUTFILE";
my $patern = shift ||"Issues:"
open my $fh, '<', $file or die "Can not open '$file': $!";
open( OUTFILE, ">", $outputfile) or die "Can not open '$outputfile': $!";
while(my $var = <$fh>) {
if(my @matches =$var=~/(.*$patern.*)/)
{
for(@matches){s/$patern//g;s/,/t/g}
print OUTFILE "@matchesn";
}
}

第二个脚本的第二个输出是:

113 114 115 116 127

现在,我想将第一个输出与按线路的第二输出匹配。我想要的结果是:如果第二个输出中的任何数字与第一个输出中的任何线匹配,则我要打印1;否则,如果该行没有匹配打印-1。

上面的输出将如下:

 1
-1
-1
-1
-1

这将您的两个脚本结合到一个脚本中。它通过$inputfile文件句柄读取,该文件指向"INPUTFILE.txt"寻找基于正则表达式($regexp)或%patterns Hash中搜索密钥的匹配。

由于比赛很简单,因此我们使用的正则表达式是使用join|和所需的搜索字符串构建的。在替代方法(在此处评论)中,我们使用哈希键自己检查是否存在搜索模式。

我在open语句中更改了变量和文件名,因为大写的文件名使它们看起来像旧样式文件句柄:

#!perl -l
my $inputfile  = "INPUTFILE.txt";
my $outputfile = "OUTPUTFILE.txt";
my $matchfile  = "MATCHFILE.txt";
open my $inputfh, '<', $inputfile  or die "No file '$inputfile': $!";
open my $matchfh, '<', $matchfile  or die "No file '$matchfile': $!n";
open my $outfh,   '>', $outputfile or die "No file '$outputfile': $!n";
my %patterns;
while (<$matchfh>) {
  $patterns{$_} = () for map { split /,/, $_ } /Issues:(.*)/;    
}
my $regex = join "|", keys %patterns;
$regex = qr/$regex/; # create a regex from %patterns
print "Search patterns : ", join " ", keys %patterns;
print "Regex           : $regex n";
while (my $line = <$inputfh>) {
  chomp $line;    
  # Print "1" for 3 digits matching search pattern; "-1" otherwise:
  #print exists $patterns{$_} ? "1" : "-1" for $line =~ m/(ddd)/g;
  # Print "1" if a matching pattern is on a line; -1 otherwise:   
  if (grep /$regex/, $line) {    #
    print "1  - $line";
  }
  else {
    print "-1 - $line";
  }
}

上面的脚本应起作用。您可以从最后一个print语句中删除- $line,然后添加文件句柄目标($outfh)以将输出引导到文件。

由于inputfile中有五行,因此输出为:

Search patterns : 127 116 114 115 113
Regex           : (?^:127|116|114|115|113) 
1 - I have never had an issue.  L_102 ----- L_127
-1 - I travel overseas ... very useful to me L_105 ----- L_134 ----- L_148
-1 - Expense to have L_522
-1 - Great benefits  L_148
-1 - prestige    L_118

nb 最终的if ... else块可以使用"三元运算符"(<cond> ? 1 : 0)缩短:

 print $line =~ /$regex/ ? '1' : '-1';

,如果$line =~ /$regex/评估为" true"(或" 1"),则" 1"将打印。如果评估为" false"(或" 0"),则将打印" -1"。

如果您从两个文件中读取并简单地用外壳重定向输出,那么所有这些的简短版本就是:

#!perl -l
my $inputfile = "INPUTFILE.txt";
my $matchfile = "MATCHFILE.txt";
open my $inputfh, '<', $inputfile or die "No '$inputfile': $!";
open my $matchfh, '<', $matchfile or die "No '$matchfile': $!n";
my %patterns;
while (<$matchfh>) {
  $patterns{$_} = () for map { split /,/, $_ } /Issues:(.*)/;
}
my $regex = join "|", keys %patterns;
$regex = qr/$regex/;
while (my $line = <$inputfh>) {
  chomp $line;
  print $line =~ $regex ? '1' : '-1';
}

最新更新