Perlを使用して2つのファイルを行ごとに連結する方法はいくつありますか?
-
06-07-2019 - |
質問
file1が次のようになっているとします:
bye bye hello thank you
そしてfile2は次のようになります:
chao hola gracias
目的の出力は次のとおりです:
bye bye chao hello hola thank you gracias
私自身は、この問題を解決するための5つの異なるアプローチをすでに考え出しています。しかし、もっと多くの方法、おそらくより簡潔でよりエレガントな方法がなければならないと思います。もっとクールなものを学べることを望みます:)
以下は、以前の問題の多くの解決策から学んだことに基づいて、私がこれまでに試したことです。また、Llamaの本から得た知識を要約したり、内在化しようとしています。
コード1:
#!perl
use autodie;
use warnings;
use strict;
open my $file1,'<','c:/file1.txt';
open my $file2,'<','c:/file2.txt';
while(defined(my $line1 = <$file1>)
and defined(my $line2 = <$file2>)){
die "Files are different sizes!\n" unless eof(file1) == eof(file2);
$line1 .= $line2;
$line1 =~ s/\n/ /;
print "$line1 \n";
}
コード2:
#!perl
use autodie;
use warnings;
use strict;
open my $file1,'<','c:/file1.txt';
my @file1 = <$file1>;
open my $file2,'<','c:/file2.txt';
my @file2 =<$file2>;
for (my $n=0; $n<=$#file1; $n++) {
$file1[$n] .=$file2[$n];
$file1[$n]=~s/\n/ /;
print $file1[$n];
}
コード3:
#!perl
use autodie;
use warnings;
use strict;
open my $file1,'<','c:/file1.txt';
open my $file2,'<','c:/file2.txt';
my %hash;
while(defined(my $line1 = <$file1>)
and defined(my $line2 = <$file2>)) {
chomp $line1;
chomp $line2;
my ($key, $val) = ($line1,$line2);
$hash{$key} = $val;
}
print map { "$_ $hash{$_}\n" } sort keys %hash;
コード4:
#!perl
use autodie;
use warnings;
use strict;
open my $file1,'<','c:/file1.txt';
open my $file2,'<','c:/file2.txt';
while(defined(my $line1 = <$file1>)
and defined(my $line2 = <$file2>)) {
$line1 =~ s/(.+)/$1 $line2/;
print $line1;
}
コード5:
#!perl
use autodie;
use warnings;
use strict;
open my $file1,'<','c:/file1.txt';
my @file1 =<$file1>;
open my $file2,'<','c:/file2.txt';
my @file2 =<$file2>;
while ((@file1) && (@file2)){
my $m = shift (@file1);
chomp($m);
my $n = shift (@file2);
chomp($n);
$m .=" ".$n;
print "$m \n";
}
次のようなことを試しました:
foreach $file1 (@file2) && foreach $file2 (@file2) {...}
しかし、Perlは構文エラーの警告をくれました。イライラしました。しかし、2つのforeach
ループを同時に実行できますか?
いつものように、コメント、提案、そしてもちろん寛大なコード共有をありがとう:)
解決
これは、任意の数のファイルで機能します:
use strict;
use warnings;
use autodie;
my @handles = map { open my $h, '<', $_; $h } @ARGV;
while (@handles){
@handles = grep { ! eof $_ } @handles;
my @lines = map { my $v = <$_>; chomp $v; $v } @handles;
print join(' ', @lines), "\n";
}
close $_ for @handles;
他のヒント
最もエレガントな方法では、perl
をまったく使用しません:
paste -d' ' file1 file2
もし私がゴルフをしていたら、 @ FMの回答として:
($,,$\)=(' ',"\n");@_=@ARGV;open $_,$_ for @_;print
map{chomp($a=<$_>);$a} @_=grep{!eof $_} @_ while @_
あなたはワンライナーに変えることができるかもしれませんが、それはただの悪です。 ;-)
さて、ここでは100文字未満です:
C:\Temp> perl -le "$,=' ';@_=@ARGV;open $_,$_ for @_;print map{chomp($a =<$_>);$a} @_=grep{!eof $_ }@_ while @_" file1 file2
丸lurみしても大丈夫(そしてなぜ<!>#8212ではなく、さまざまな方法を 探しているのであれば)、私はその道を発見したと思います狂気:
@_=@ARGV;chomp($x[$.-1]{$ARGV}=$_) && eof
and $.=0 while<>;print "@$_{@_}\n" for @x
C:\Temp> perl -e "@_=@ARGV;chomp($x[$.-1]{$ARGV}=$_) && eof and $.=0 while<>;print qq{@$_{@_}\n} for @x" file1 file2
出力:
bye bye chao hello hola thank you gracias
任意の行数を許可し、ファイルの行数が異なるかどうかを気にしない Code 5 の簡単な代替手段:
#!/usr/bin/perl
use strict; use warnings;
use File::Slurp;
use List::AllUtils qw( each_arrayref );
my @lines = map [ read_file $_ ], @ARGV;
my $it = each_arrayref @lines;
while ( my @lines = grep { defined and chomp and length } $it->() ) {
print join(' ', @lines), "\n";
}
そして、外部モジュールを使用しない:
#!perl
use autodie; use warnings; use strict;
my ($file1, $file2) = @ARGV;
open my $file1_h,'<', $file1;
my @file1 = grep { chomp; length } <$file1_h>;
open my $file2_h,'<', $file2;
my @file2 = grep { chomp; length } <$file2_h>;
my $n_lines = @file1 > @file2 ? @file1 : @file2;
for my $i (0 .. $n_lines - 1) {
my ($line1, $line2) = map {
defined $_ ? $_ : ''
} $file1[$i], $file2[$i];
print $line1, ' ', $line2, "\n";
}
両方のファイルに表示される行のみを連結する場合:
#!perl
use autodie; use warnings; use strict;
my ($file1, $file2) = @ARGV;
open my $file1_h,'<', $file1;
my @file1 = grep { chomp; length } <$file1_h>;
open my $file2_h,'<', $file2;
my @file2 = grep { chomp; length } <$file2_h>;
my $n_lines = @file1 < @file2 ? @file1 : @file2;
for my $i (0 .. $n_lines - 1) {
print $file1[$i], ' ', $file2[$i], "\n";
}
最小限のエラーチェックを備えた簡単なもの:
#!/usr/bin/perl -w
use strict;
open FILE1, '<file1.txt';
open FILE2, '<file2.txt';
while (defined(my $one = <FILE1>) or defined(my $twotemp = <FILE2>)){
my $two = $twotemp ? $twotemp : <FILE2>;
chomp $one if ($one);
chomp $two if ($two);
print ''.($one ? "$one " : '').($two ? $two : '')."\n";
}
いいえ、同じスレッド内で2つのループを同時に実行することはできません。fork
する必要がありますが、同期的に実行されることは保証されません。