簡體   English   中英

比較2個散列中的2個已處理密鑰

[英]Comparing between 2 processed keys in 2 hashes

我想讀取帶有一些符號的文件,例如“!”。 和“ ^”,並希望在將它們與另一行中的其他字符串進行比較之前將其刪除。 如果刪除符號后兩個字符串都相同,我想將它們存儲在另一個稱為“ common”的哈希中。 例如... FileA:

hello!world
help?!3233
oh no^!!
yes!

文件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);

我在哈希中打印出了鍵,並顯示了正確的結果(即,它將FileA轉換為“你好,幫助?,哦,不是,是的)。但是,當我使用以下代碼對FileA和FileB進行比較時,總是失敗。

while(($key,$value)=each(%config))
{
    $num=keys(%base_config);
    $num--;#to get the correct index
    while($num>=0)
    {
        $common{$value}=$value if exists $read_file{$key};#stored the correct matches in %common
        $num--;
    }
}

我嘗試使用以下示例測試我的替換並在2個字符串之間進行比較,並且它可以正常工作。 我不知道為什么無法將字符串從文件中讀取為哈希值。

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”之前。

首先,我們必須規范您的輸入。 下面的代碼為每個路徑創建一個哈希。 對於給定文件中的每一行,請刪除從第一行開始的所有內容! ^字符並記錄其存在。

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;
}

Perl FAQ列表的“ 數據處理”部分介紹了計算兩個數組的交集 使技術適應您的情況,我們想知道所有輸入共用的線。

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

您可以使用正則表達式字符類s / [?^] // g刪除^和?,請注意^必須是組中的最后一個,否則需要對其進行轉義。 (為了避免以后再添加其他字符,這樣做可能更安全,以免被否定)。

我處理所有文件,使用散列來計算單詞存在的文件。

為了比較差異,我使用2 **(文件數),因此我得到的值是2 ** 0 = 1、2 ** 1 = 2、2 ** 2 = 4,依此類推。 我用來顯示字符串屬於哪個文件。 如果它們全部存在,它們將等於文件總數,因此在這種情況下為2-3(2 + 1)表示它們都在兩個文件中,1表示僅FileA,2表示FileB。 您可以通過按位 (&)進行檢查。

編輯:添加了測試條件

<!-- 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";
    }
}

輸出:

    bahbah 2: FileB.txt
   chucker 1: FileA.txt
     hello 3: FileA.txt FileB.txt
      help 3: FileA.txt FileB.txt
  marymary 2: FileB.txt
     oh no 3: FileA.txt FileB.txt
      test 1: FileA.txt
       yes 3: FileA.txt FileB.txt

Testing Words: hello^vsd chuck help? test marymary^
Found: hello
Cannot find: chuck
Found: help
Cannot find: test
Found: marymary

這是另一種同時讀取兩個文件的解決方案(假設兩個文件的行數相等):

use strict;
use warnings;

our $INVALID = '!\^'; #regexp character class, must escape

my $fileA = "file1.txt";
my $fileB = "file2.txt";

sub readl
{
  my $fh = shift;
  my $ln = "";

  if ($fh and $ln = <$fh>)
  {
    chomp $ln;
    $ln =~ s/[$INVALID]+.*//g;
  }

  return $ln;
}

my ($fhA, $fhB);
my ($wdA, $wdB);
my %common = ();

open $fhA, $fileA or die "$!\n";
open $fhB, $fileB or die "$!\n";

while ($wdA = readl($fhA) and $wdB = readl($fhB))
{
  $common{$wdA} = undef if $wdA eq $wdB;
}

print "$_\n" foreach keys %common;

輸出量

andrew@gidget:comparefiles$ cat file1.txt 
hello!world
help?!3233
oh no^!!
yes!

andrew@gidget:comparefiles$ cat file2.txt 
hello
help?
oh no
yes

andrew@gidget:comparefiles$ perl comparefiles.pl 
yes
oh no
hello
help?

首先將可重用段包裝到子例程中:

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
}

read_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?

如果要測試它,可以按以下方式定義your_file_names_here

sub your_file_names_here {\(<<'/A', <<'/B')}
hello!world
help?!3233
oh no^!!
yes!
/A
hello
help?
oh no
yes
/B

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM