2

我有两个文本文件 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,而不是不匹配的内容。请帮帮我。

4

5 回答 5

1

您的主要问题是您未定义输入记录分隔符$/。这意味着整个文件将作为单个字符串读取,您所能做的就是说这两个文件是不同的。

删除undef $/,事情会工作得更好。然而,内部for循环将读取并打印所有file2file1. 第二次遇到此循环时,已从文件中读取所有数据,因此根本不会执行循环体。您必须file2在外部循环内打开或将文件读入数组并循环遍历该数组。

再说一次,你真的想打印file2不等于每一行的所有行file1吗?

更新

正如我在评论中所写,听起来您想输出text1text2. 使用哈希很容易实现:

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
于 2013-02-06T07:58:59.667 回答
1

这是我的计划:

  1. 读取哈希中第一个文件的内容,并带有出现次数的计数器。例如,使用您获得的数据:

    %lines = ( 'ac' => 1,
        'abc' => 1,
        'abcd' => 1,
        'abcde' => 1);
    
  2. 读取第二个文件,如果 key 存在则删除之前的 hash %lines。

  3. 将密钥打印%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;
于 2013-02-06T07:28:54.267 回答
1

我认为您应该读取数组中的 text2 ,然后在该数组的第二个 foreach 中使用该数组。

@b = <SEA>;

否则在第二个循环中,文件指针已经在末尾

于 2013-02-06T07:05:33.963 回答
1

单程:

#!/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$x\E$/,@arr2));
}

close $fh1;
close $fh2;
close $out;

执行上述操作后,文件“file3”包含:

$ cat file3
ac
abcde
于 2013-02-06T07:06:06.327 回答
0

我想这样查看您的问题:

  • 你有一组S中的字符串file.txt
  • 你有一组F中的禁止字符串forbidden.txt
  • 你想要允许的字符串,所以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>;

set 减号的工作方式类似于以下任何一种方式:

  • 对于S中的每个元素x,当x不在F中时,x在结果集R中。

    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.

于 2013-02-06T08:45:00.610 回答