2

以下のような2つのテキストファイルtext1.txtとtext2.txtがあります

文1

    ac
    abc
    abcd
    abcde

テキスト2

    ab
    abc
    acd
    abcd

出力

ac
abcde

2 つのファイルを比較し、text12 番目のファイルに一致するコンテンツを削除する必要があります。

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

これが私の計画です:

  1. オカレンスのカウンターを使用して、ハッシュ内の最初のファイルの内容を読み取ります。たとえば、次のデータを処理します。

    %lines = ( 'ac' => 1,
        'abc' => 1,
        'abcd' => 1,
        'abcde' => 1);
    
  2. 2番目のファイルを読み取り、キーが存在する場合は前のハッシュ%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 を読み取ってから、その配列の 2 番目の foreach で配列を使用する必要があると思います。

@b = <SEA>;

または、2 番目のループで、ファイル ポインタが既に最後にある

于 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 に答える
1

あなたの主な問題は、入力レコードセパレーターを定義していないことです$/。これは、ファイル全体が 1 つの文字列として読み取られることを意味し、できることは 2 つのファイルが異なるということだけです。

削除するundef $/と、物事がはるかにうまく機能します。ただし、内側のforループはfile2、 の最初の行と一致しないすべての行を読み取って出力しますfile1。このループが 2 回目に発生すると、すべてのデータがファイルから読み取られているため、ループの本体はまったく実行されません。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
于 2013-02-06T07:58:59.667 に答える
0

あなたの問題を次のように表示したいと思います。

  • に文字列のセットSfile.txtがあります。
  • に禁止文字列のセットFforbidden.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>;

セット マイナスは、次のいずれかの方法で機能します。

  • 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 に答える