我有两个文本文件 text1.txt 和 text2.txt如下所示
文本1
ac
abc
abcd
abcde
文本2
ab
abc
acd
abcd
输出
ac
abcde
我需要比较两个文件,并在第二个文件中有匹配项时从text1
中删除内容。
我想要Perl中的代码。目前我正在尝试以下代码。
#!usr/bin/perl
use strict;
use warnings;
open (GEN, "text1.txt") || die ("cannot open general.txt");
open (SEA, "text2.txt") || die ("cannot open search.txt");
open (OUT,">> output.txt") || die ("cannot open intflist.txt");
open (LOG, ">> logfile.txt");
undef $/;
foreach (<GEN>) {
my $gen = $_;
chomp ($gen);
print LOG $gen;
foreach (<SEA>) {
my $sea = $_;
chomp($sea);
print LOG $sea;
if($gen ne $sea) {
print OUT $gen;
}
}
}
在此,我从text1
获得所有内容,而不是无与伦比的内容。请帮帮我。
我认为您应该读取数组中的 text2,然后在该数组的第二个 foreach 中使用该数组。
@b = <SEA>;
否则在第二个循环中,文件指针已经位于末尾
一种方式:
#!/usr/bin/perl
use strict;
use warnings;
$="n";
open my $fh1, '<', 'file1' or die $!;
open my $fh2, '<', 'file2' or die $!;
open my $out, '>', 'file3' or die $!;
chomp(my @arr1=<$fh1>);
chomp(my @arr2=<$fh2>);
foreach my $x (@arr1){
print $out $x if (!grep (/^Q$xE$/,@arr2));
}
close $fh1;
close $fh2;
close $out;
执行上述操作后,文件 'file3' 包含:
$ cat file3
ac
abcde
的计划:
以哈希形式读取第一个文件的内容,并带有出现次数计数器。例如,使用数据可以获得:
%lines = ( 'ac' => 1, 'abc' => 1, 'abcd' => 1, 'abcde' => 1);
读取第二个文件,如果键存在,则删除前面的哈希 %lines 。
- 将密钥
%lines
打印到所需的文件。
例:
use strict;
open my $fh1, '<', 'text1' or die $!;
open my $fh2, '<', 'text2' or die $!;
open my $out, '>', 'output' or die $!;
my %lines = ();
while( my $key = <$fh1> ) {
chomp $key;
$lines{$key} = 1;
}
while( my $key = <$fh2> ) {
chomp $key;
delete $lines{$key};
}
foreach my $key(keys %lines){
print $out $key, "n";
}
close $fh1;
close $fh2;
close $out;
您的主要问题是您未定义输入记录分隔符$/
。这意味着整个文件将作为单个字符串读取,您所能做的就是说这两个文件不同。
删除undef $/
,事情会好得多。但是,内部for
循环将读取并打印file2
中与file1
的第一行不匹配的所有行。第二次遇到此循环时,已从文件中读取所有数据,因此根本不会执行循环的主体。您必须在外部循环中打开file2
,或者将文件读入数组并循环访问该数组。
再说一次,您真的要打印file2
中不等于file1
中每一行的所有行吗?
更新
正如我在评论中所写,听起来您想输出text1
中没有出现在text2
任何地方的行.使用哈希可以轻松实现:
use strict;
use warnings;
my %exclude;
open my $fh, '<', 'text2.txt' or die $!;
while (<$fh>) {
chomp;
$exclude{$_}++;
}
open $fh, '<', 'text1.txt' or die $!;
while (<$fh>) {
chomp;
print "$_n" unless $exclude{$_};
}
使用您在问题中显示的数据,将产生此输出
ac
abcde
这样看待你的问题:
- 您在
file.txt
中有一组字符串 S。 - 您在
forbidden.txt
中有一组禁止字符串的 F。 - 你想要允许的字符串,所以 S \ F (setminus(。
Perl 中有一个数据结构,它实现了一组字符串:哈希。(它也可以映射到标量,但这在这里是次要的(。
因此,首先我们创建我们拥有的行集。我们让该文件中的所有字符串映射到 undef
,因为我们不需要该值:
open my $FILE, "<", "file.txt" or die "Can't open file.txt: $!";
my %Set = map {$_ => undef} <$FILE>;
我们以相同的方式创建禁止集:
open my $FORBIDDEN, "<", "forbidden.txt" or die "Can't open forbidden.txt: $!";
my %Forbidden = map {$_ => undef} <$FORBIDDEN>;
集合减号的工作方式类似于以下任一方式:
对于 S 中的每个元素 x,x 在结果集中 R iff x 不在 F 中。
my %Result = map {$_ => $Set{$_}} grep {not exists $Forbidden{$_}} keys %Set;
结果集 R 最初为 S。对于 F 中的每个元素,我们从 R 中删除该项:
my %Result = %Set; # make a copy delete $Result{$_} for keys %Forbidden;
(keys
函数访问字符串集中的元素(
然后我们可以打印出所有密钥:print keys %Result
.
但是,如果我们想维护秩序呢?哈希中的条目也可以携带关联的值,那么为什么不能携带行号呢?我们像这样创建集合 S:
open my $FILE, "<", "file.txt" or die "Can't open file.txt: $!";
my $line_no = 1;
my %Set = map {$_ => $line_no++} <$FILE>;
现在,这个值与字符串一起携带,我们可以在最后访问它。具体来说,我们将哈希中的键在其行号之后进行排序:
my @sorted_keys = sort { $Result{$a} <=> $Result{$b} } keys %Result;
print @sorted_keys;
注意:所有这些都假定文件由换行符终止。否则,您将不得不chomp
.