我想在文件中读取一些符号,如“!”和“^”并希望在将它们与另一行的其他字符串进行比较之前删除它们。如果删除符号后两个字符串相同,我想将它们存储在另一个名为“common”的哈希中。 例如... FILEA:
hello!world
help?!3233
oh no^!!
yes!
FILEB:
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--;
}
}
我尝试测试我的替换并使用以下示例比较两个字符串,并且它有效。我不知道为什么它不能从字符串中读取字符串中的字符串。
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};
两个文件可以具有不同数量的文本行,并且搜索时文本行不需要具有相同的顺序。即。 “哦不”可以在“你好”之前来到。
答案 0 :(得分:0)
你可以使用正则表达式字符类s / [?^] // g来删除^和?,注意^需要是组中的最后一个,或者你需要转义它。 (如果你以后添加其他字符,可能会更安全地逃避它,所以它们不会被否定)。
我处理所有文件,使用哈希来计算单词存在的文件。
为了比较差异,我使用2 **(文件数量),因此我得到值2 ** 0 = 1,2 ** 1 = 2,2 ** 2 = 4,依此类推。我用来显示字符串属于哪个文件。如果它们总共存在,则它们将等于总文件数,因此在这种情况下为2 - 3(2 + 1)表示它们在两个文件中,1表示仅FileA,2表示FileB。你可以通过按位和(&amp;)来检查这个。
编辑:添加了测试条件
<!-- 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
答案 1 :(得分:0)
这是另一种同时读取两个文件的解决方案(假设两个文件的行数相同):
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?
答案 2 :(得分:0)
首先将可重用的段打包成子例程:
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
答案 3 :(得分:0)
首先,我们必须规范您的输入。下面的代码为每个路径创建一个哈希。对于给定文件中的每一行,请删除以第一个!
或^
字符开头的所有内容并记录其存在。
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;
}
Computing the intersection of two arrays的Data Manipulation部分涵盖了Perl FAQ list。根据您的情况调整技术,我们想知道所有输入共有的行。
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