0

2つのタブで区切られたファイルがあり、それらを揃える必要があります。例えば:

File 1:      File 2:
AAA 123      BBB 345
BBB 345      CCC 333
CCC 333      DDD 444

(これらは大きなファイルであり、数千行になる可能性があります!)

私がやりたいのは、出力を次のようにすることです。

AAA 123
BBB 345  BBB 345
CCC 333  CCC 333
         DDD 444

できればperlでこれを実行したいのですが、方法がわかりません。どんな助けでも大いに感謝されるでしょう。

4

4 に答える 4

1

データ構造を作成するだけであれば、これは非常に簡単です。

#!/usr/bin/env perl

# usage: script.pl file1 file2 ...

use strict;
use warnings;

my %data;
while (<>) {
  chomp;
  my ($key, $value) = split;
  push @{$data{$key}}, $value;
}

use Data::Dumper;
print Dumper \%data;

その後、任意の形式で出力できます。ファイルをそのまま使用することが本当に重要な場合は、もう少し注意が必要です。

于 2012-05-03T20:13:49.800 に答える
0

ファイルがソートされていると仮定すると、

sub get {
   my ($fh) = @_;
   my $line = <$fh>;
   return () if !defined($line);
   return split(' ', $line);
}

my ($key1, $val1) = get($fh1);
my ($key2, $val2) = get($fh2);

while (defined($key1) && defined($key2)) {
   if ($key1 lt $key2) {
       print(join("\t", $key1, $val1), "\n");
       ($key1, $val1) = get($fh1);
   }
   elsif ($key1 gt $key2) {
       print(join("\t", '', '', $key2, $val2), "\n");
       ($key2, $val2) = get($fh2);
   }
   else {
       print(join("\t", $key1, $val1, $key2, $val2), "\n");
       ($key1, $val1) = get($fh1);
       ($key2, $val2) = get($fh2);
   }
}

while (defined($key1)) {
   print(join("\t", $key1, $val1), "\n");
   ($key1, $val1) = get($fh1);
}

while (defined($key2)) {
   print(join("\t", '', '', $key1, $val1), "\n");
   ($key2, $val2) = get($fh2);
}
于 2012-05-03T19:21:33.240 に答える
0

Joel Berger の回答に似ていますが、このアプローチにより、ファイルに特定のキーが含まれているか含まれていないかを追跡できます。

my %data;

while (my $line = <>){
    chomp $line;
    my ($k)          = $line =~ /^(\S+)/;
    $data{$k}{line}  = $line;
    $data{$k}{$ARGV} = 1;
}

use Data::Dumper;
print Dumper(\%data);

出力:

$VAR1 = {
  'CCC' => {
    'other.dat' => 1,
    'data.dat' => 1,
    'line' => 'CCC 333'
  },
  'BBB' => {
    'other.dat' => 1,
    'data.dat' => 1,
    'line' => 'BBB 345'
  },
  'DDD' => {
    'other.dat' => 1,
    'line' => 'DDD 444'
  },
  'AAA' => {
    'data.dat' => 1,
    'line' => 'AAA 123'
  }
};
于 2012-05-03T20:26:52.840 に答える
0

池上が述べたように、ファイルの内容があなたの例に示すように配置されていることを前提としています。

use strict;
use warnings;

open my $file1, '<file1.txt' or die $!;
open my $file2, '<file2.txt' or die $!;

my $file1_line = <$file1>;
print $file1_line;

while ( my $file2_line = <$file2> ) {
    if( defined( $file1_line = <$file1> ) ) {
        chomp $file1_line;
        print $file1_line;
    }

    my $tabs = $file1_line ? "\t" : "\t\t";
    print "$tabs$file2_line";
}

close $file1;
close $file2;

例を確認すると、両方のファイルに同一のキーと値のペアがいくつか表示されます。これを考えると、ファイル 1 に固有のペア、ファイル 2 に固有のペア、および共通のペアを表示したいようです。この場合 (そして、ファイルのペアをキーまたは値で一致させようとしていない場合)、次のことができます。use List::Compare:

use strict;
use warnings;
use List::Compare;

open my $file1, '<file1.txt' or die $!;
my @file1 = <$file1>;
close $file1;

open my $file2, '<file2.txt' or die $!;
my @file2 = <$file2>;
close $file2;

my $lc = List::Compare->new(\@file1, \@file2);

my @file1Only = $lc->get_Lonly; # L(eft array)only
for(@file1Only) { print }

my @bothFiles = $lc->get_intersection;
for(@bothFiles) { chomp; print "$_\t$_\n" }

my @file2Only = $lc->get_Ronly; # R(ight array)only
for(@file2Only) { print "\t\t$_" }
于 2012-05-03T20:01:56.093 に答える