Wie viele verschiedene Möglichkeiten gibt es zwei Linien Dateien verketten für Zeile mit Perl?

StackOverflow https://stackoverflow.com/questions/1636755

  •  06-07-2019
  •  | 
  •  

Frage

Nehmen wir an file1 sieht wie folgt aus:

bye bye
hello
thank you

Und file2 sieht wie folgt aus:

chao
hola
gracias

Die gewünschte Ausgabe ist dies:

bye bye chao
hello hola
thank you gracias

Ich selbst habe bereits mit fünf verschiedenen Ansätze kommen, um dieses Problem zu lösen. Aber ich denke, es muss mehr Möglichkeiten geben, wahrscheinlich knapper und elegantere Wege, und ich hoffe, ich kann mehr coole Sachen lernen:)

Im Folgenden ist das, was ich bisher versucht haben, auf das, was ich von den vielen Lösungen meiner früheren Probleme gelernt. Auch ich versuche, irgendwie zu verdauen oder internalisieren das Wissen, das ich aus dem Lama-Buch erworben haben.

Code 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";
}

Code 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];
}

Code 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;

Code 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;
}

Code-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";
}

Ich habe so etwas wie dies versucht:

foreach $file1 (@file2) && foreach $file2 (@file2) {...}

Aber Perl gab mir eine syntaktische Fehler Warnung. Ich war frustriert. Aber können wir laufen zwei foreach gleichzeitig Schleifen?

Danke, wie immer, für alle Kommentare, Anregungen und natürlich auch das großzügigen Code-Sharing:)

War es hilfreich?

Lösung

Dies funktioniert für eine beliebige Anzahl von Dateien:

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;

Andere Tipps

Die eleganteste Art und Weise ist nicht mit perl überhaupt:

paste -d' ' file1 file2

Wenn ich ein Golf-Mann wäre, könnte ich umschreiben @ FM Antwort wie:

($,,$\)=(' ',"\n");@_=@ARGV;open $_,$_ for @_;print
map{chomp($a=<$_>);$a} @_=grep{!eof $_} @_ while @_

, die Sie vielleicht in der Lage sein, sich in eine Einzeiler, aber das ist einfach nur böse. ; -)

Nun, hier ist es, unter 100 Zeichen:

C:\Temp> perl -le "$,=' ';@_=@ARGV;open $_,$_ for @_;print map{chomp($a =<$_>);$a} @_=grep{!eof $_ }@_ while @_" file1 file2

Wenn es OK schlürfen (und warum zum Teufel nicht - we ist für verschiedene Arten suchen), ich glaube, ich den Weg den Wahnsinn entdeckt habe:

@_=@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

Ausgabe:

bye bye chao
hello hola
thank you gracias

Eine einfachere Alternative zu Ihrem Code-5 , die für eine beliebige Anzahl von Linien erlaubt und kümmert sich nicht darum, ob die Dateien unterschiedliche Anzahl von Zeilen (Hut Spitze @FM) haben:

#!/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";
}

Und ohne externe Module mit:

#!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";
}

Wenn Sie nur die Zeilen verketten möchten, die in beiden Dateien angezeigt werden:

#!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";
}

Ein leicht mit minimaler Fehlerprüfung:

#!/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";
}

Und nein, kann man nicht zwei Schleifen gleichzeitige innerhalb des gleichen Thread ausgeführt, dann würden Sie fork haben, aber das ist nicht synchron laufen würde gewährleistet.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top