String 比较2个哈希中的2个已处理密钥

String 比较2个哈希中的2个已处理密钥,string,perl,hash,String,Perl,Hash,我想在文件中读取一些符号,如“!”和“^”,并想在将它们与另一行的其他字符串进行比较之前删除它们。如果删除符号后两个字符串相同,我想将它们存储在另一个名为“common”的散列中。 例如 文件A: 文件B: hello help? oh no yes 在这种情况下,FileA和FileB应该是相同的,因为我正在比较字符到出现“!”或“^”的位置。 我使用以下代码读取文件: open FILEA, "< script/".$fileA or die; my %read_file; whil

我想在文件中读取一些符号,如“!”和“^”,并想在将它们与另一行的其他字符串进行比较之前删除它们。如果删除符号后两个字符串相同,我想将它们存储在另一个名为“common”的散列中。 例如 文件A:

文件B:

hello
help?
oh no
yes
在这种情况下,FileA和FileB应该是相同的,因为我正在比较字符到出现“!”或“^”的位置。 我使用以下代码读取文件:

open FILEA, "< script/".$fileA or die;
my %read_file;
while (my $line=<FILEA>) {
   (my $word1,my $word2) = split /\n/, $line;
   $word1 =~ s/(!.+)|(!.*)|(\^.+)|(\^.*)//;#to remove ! and ^
   $read_file{$word1} = $word1;
}
close(FILEA);
我试着用下面的例子测试我的替换和比较两个字符串,结果很好。我不知道为什么从文件中将字符串读入哈希不起作用

use strict;
use warnings;

my $str="hello^vsd";
my $test="hello";
$str =~ s/(!.+)|(!.*)|(\^.+)|(\^.*)//;
my %hash=();
$hash{$str}=();
foreach my $key(keys %hash)
{
    print "$key\n";
}
print "yay\n" if exists $hash{$test};
print "boo\n" unless exists $hash{$test};

两个文件可以有不同数量的文本行,搜索时文本行的顺序不必相同。例如,“噢,不”可以出现在“hello”之前。

您可以使用正则表达式字符类s/[?^]//g来删除“^”和“?”,请注意,^必须是组中的最后一个字符,否则需要转义它。(转义它可能更安全,以防以后添加其他字符,这样它们就不会被否定)

我处理所有文件,使用散列计算单词存在的文件

为了比较差异,我使用了2**(#of file),所以我得到了值2**0=1、2**1=2、2**2=4,依此类推。我用来显示字符串属于哪个文件。如果它们存在于所有文件中,它们将等于总文件数,因此在本例中,2-3(2+1)表示它们同时存在于两个文件中,1表示仅存在于文件A中,2表示存在于文件B中。您可以通过按位and(&)进行检查

编辑:添加了测试条件

<!-- language: perl -->

my @files = qw(FileA.txt FileB.txt);
my %words;
foreach my $i (0 .. $#files) {
    my $file = $files[$i];
    open(FILE,$file) or die "Error: missing file $file\n$!\n";
    while (<FILE>) {
        chomp;
        next if /^$/;
        my ($word) = split /[!\^]/;
        $word =~ s/[?\^]//g; # removes ^ and ?
        $words{$word} += 2**$i;
    }
    close(FILE);
}

my %common;
foreach my $key (sort keys %words) {
    my @found;
    foreach my $i (0 .. $#files) {
        if ( $words{$key} & 2**$i ) { push @found, $files[$i] }
    }
    if ( $words{$key} & 2**$#files ) { $common{$key}++ }
    printf "%10s %d: @found\n",$key,$words{$key};
}

my @tests = qw(hello^vsd chuck help? test marymary^);
print "\nTesting Words: @tests\n";
foreach (@tests) {
    my ($word) = split /[!\^]/;
    $word =~ s/[?\^]//g; # removes ^ and ?
    if ( exists $common{ $word } ) {
        print "Found: $word\n";
    }
    else {
        print "Cannot find: $word\n";
    }
}

下面是另一个同时读取两个文件的解决方案(假设两个文件的行数相等):


首先,将可重用段打包到子例程中:

sub read_file {
    open my $fh, "<", $_[0] or die "read_file($_[0]) error: $!";
      # lexical handles auto-close when they fall out of scope
      # and detailed error messages are good
    my %file;
    while (my $line = <$fh>) {
        chomp $line;          # remove newline
        $line =~ s{[!^].*}{}; # remove everything starting from ! or ^
        $file{$line}++;
    }
    \%file
}
将打印:

common: yes common: oh no common: hello common: help?
首先,我们必须规范您的输入。下面的代码为每个路径创建一个哈希。对于给定文件中的每一行,删除从第一个
开始的所有内容
^
字符并记录其存在

sub read_inputs {
  my @result;

  foreach my $path (@_) {
    my $data = {};

    open my $fh, "<", $path or die "$0: open $path: $!";
    while (<$fh>) {
      chomp;
      s/[!^].*//;  # don't put the caret first without escaping!
      ++$data->{$_};
    }

    push @result, $data;
  }

  wantarray ? @result : \@result;
}
把它绑在一起

my @input = read_inputs "FileA", "FileB";
my @common = common @input;
print "$_\n" for sort @common;
输出

hello help? oh no yes 你好 帮忙? 哦,不
是的,您是否认为文件A中的每一行都应该与文件B中的对应行进行比较?文件A和文件B的行数相等吗?不。文件A和文件B可以有不同的行数,并且行的顺序不必相同。嗨。我刚开始学习Perl,不太理解“my($fileA,$fileB)=map{read_file$}your_file_names_here();”您能进一步解释吗?
map
对列表应用转换并返回转换后的列表。它与
my$fileA=read_文件('fileA.txt')相同;my$fileB=read_文件('fileB.txt')
如果列表
('filea.txt','fileb.txt')
是由
您的文件名\u在这里返回的
占位符。
sub read_file {
    open my $fh, "<", $_[0] or die "read_file($_[0]) error: $!";
      # lexical handles auto-close when they fall out of scope
      # and detailed error messages are good
    my %file;
    while (my $line = <$fh>) {
        chomp $line;          # remove newline
        $line =~ s{[!^].*}{}; # remove everything starting from ! or ^
        $file{$line}++;
    }
    \%file
}
my ($fileA, $fileB) = map {read_file $_} your_file_names_here();

my %common;
$$fileA{$_} and $common{$_}++ for keys %$fileB;

print "common: $_\n" for keys %common;
common: yes common: oh no common: hello common: help?
sub your_file_names_here {\(<<'/A', <<'/B')}
hello!world
help?!3233
oh no^!!
yes!
/A
hello
help?
oh no
yes
/B
sub read_inputs {
  my @result;

  foreach my $path (@_) {
    my $data = {};

    open my $fh, "<", $path or die "$0: open $path: $!";
    while (<$fh>) {
      chomp;
      s/[!^].*//;  # don't put the caret first without escaping!
      ++$data->{$_};
    }

    push @result, $data;
  }

  wantarray ? @result : \@result;
}
sub common {
  my %matches;
  for (@_) {
    ++$matches{$_} for keys %$_;
  }

  my @result = grep $matches{$_} == @_, keys %matches;
  wantarray ? @result : \@result;
}
my @input = read_inputs "FileA", "FileB";
my @common = common @input;
print "$_\n" for sort @common;
hello help? oh no yes