[英]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.