2010-12-29 3 views
0

Я хочу прочитать в двух входных файлах и вывести новый файл, содержащий одну строку, которая является конкатенацией каждой соответствующей строки из двух входных файлов.Как объединить два файла в Perl?

Например:

линии 1 нового выходного файла будет иметь:

info from input file 1, line 1 some number of tabs info from input file 2, line 1 
. 
. 
. 

Если какой-либо входной файл имеет больше строк, чем другие остальные строки должны быть вставлены в выходной файл в правильном положении.

Спасибо.

+2

Какие исследования вы делали, и где вы застряли? – bzlm

+3

Вы в системе * NIX? 'perl -e 'exec @ARGV' paste/tmp/file1/tmp/file2' :) – pilcrow

+0

@pilcrow: Да, я нахожусь в * NIX, и ваше решение работает нормально. Я не могу поверить, что сам не придумал. Я сделал исследование перед публикацией, но забыл рассмотреть команду paste. Благодарю. –

ответ

1
open FP1,"filename1"; 
open FP2,"filename2"; 
my ($l1,$l2); 
while(1) 
{ 
    $l1=<FP1>; chomp $l1; 
    $l2=<FP2>; chomp $l2; 
    last unless(defined $l1 or defined $l2); 
    print $l1.$l2,"\n"; 
} 
close FP2; 
close FP1; 
+0

Спасибо. Это было очень полезно. –

+8

Пожалуйста, не указывайте пример кода, в котором используются дескрипторы файлов с открытым словом, или форма 2 arg open, или пренебрежение проверкой возврата open. Все они очень обескуражены. –

+2

@ Ven'Tatsu: ... и я не сказал: «Используйте строгие, используйте предупреждения»; и я не справился с тем, что файлы не могут быть открыты и т. д. bla, bla, bla, .... Есть тысячи вещей, которые вы всегда можете навязать любому скрипту Perl, потому что он не удовлетворяет чей-то вкус. Пожалуйста, не будьте настолько придирчивы! – Curd

0

Сначала вы можете запросить (с wc -l), в файле которого больше строк. Предполагая (для псевдокода), что файл 1 имеет несколько линий, то сделайте следующее:

use strict; 
use warnings; 

open(my $fh,"<","file 1") or die ("Couldn't open file 1: $!"); 
open(my $write,">","output.csv") or die ("Couldn't open output.csv: $!"); 

my $str; 
my $count=1; 

while(my $line=<$fh>) 
{ 
    $str=`head -n $count file 2 | tail -n 1`. (\tx[however many tabs you want]) . $line; 
    print $write $str; 
    $count++; 
} 

close($fh); 
close($write); 
+0

Спасибо. Это было очень полезно. –

+0

Добро пожаловать. Однако я сделал первую часть $ str (использование '' echo -n $ count file 2'' не даст вам то, что вы хотите). Я починил это. –

1

Это действительно не отличается то, что зацикливание через один файл, пока вы обратите внимание на несколько трюков в Perl. Для одного файла он обычно используется

use strict; 
use warnings; 
use English qw(-no_match_vars); 

my $filename = 'foo'; 
open my $file, '<', $filename or die "Failed to open '$filename' $OS_ERROR\n"; 

while (my $line = <$file>) { 
    # work with $line 
} 

close $file; 

Это может быть расширена до двух файлов, открыв как и изменение контура условного только конец, когда оба файла делается чтение. Но есть уловка, когда Perl видит простое чтение из дескриптора файла в качестве условного для цикла while, он обертывает его в defined() для вас, поскольку условное выражение теперь более, чем простое чтение, это нужно делать вручную.

use strict; 
use warnings; 
use English qw(-no_match_vars); 

my $filename1 = 'foo'; 
my $filename2 = 'bar'; 
open my $file1, '<', $filename1 or die "Failed to open '$filename1' $OS_ERROR\n"; 
open my $file2, '<', $filename2 or die "Failed to open '$filename2' $OS_ERROR\n"; 

my ($line1, $line2); 
while (do { $line1 = <$file1>; $line2 = <$file2>; defined($line1) || defined($line2) }) { 
    # do what you need to with $line1 and $line2 
} 

close $file1; 
close $file2; 
+0

Очень интересно. Но не остановится ли этот цикл, прежде чем проходить через все строки обоих файлов, если один файл имеет меньше строк, чем другой? –

+1

Нет. Например, если файл 1 имеет 100 строк, а файл 2 имеет 90 строк, тогда $ line2 будет определен только для первых 90 итераций, а $ line1 будет определен для всех 100 итераций. Однако «или» (т.е. ||) гарантирует, что мы пропустим все 100 итераций. –

+1

Обратите внимание, что на двух открытых операторах '>' должно быть «<». Эти два файла являются входными файлами, а не выходными файлами. Хороший способ случайно удалить данные в ваших файлах. –

1

Мне нравятся хеши для агрегирования вещей. Это быстро, если не особенно элегантно.

#!perl 
use strict; 
use warnings; 

my ($file1, $file2) = @ARGV; 
die "usage: $0 file1 file2\n" 
    unless $file1 && $file2; 

use File::Slurp; 
my @a = read_file($file1) 
    or die "couldn't read $file1 - $!"; 
my @b = read_file($file2) 
    or die "couldn't read $file2 - $!"; 

my $combined = {}; # hashref 

my $i=0; 
foreach (@a) { 
    chomp; 
    $combined->{$i}{b} = '' unless defined $combined->{$i}{b}; 
    $combined->{$i++}{a} = $_; 
} 

$i=0; 
foreach (@b) { 
    chomp; 
    $combined->{$i}{a} = '' unless defined $combined->{$i}{a}; 
    $combined->{$i++}{b} = $_; 
} 

foreach my $i (sort {$a<=>$b} keys %$combined) { 
    print $combined->{$i}{a}, ("\t" x 2), $combined->{$i}{b}, "\n"; 
} 
+0

Да, это очень элегантно и хорошо пример применения хешей для реализации решения. Спасибо. –

+0

Ну, да, спасибо, или, пожалуйста, @Horace – Nathan

+0

Теперь, когда я думаю об этом, массив хэшей может быть b чем этот хэш хешей. Вам не пришлось бы возиться с сортировкой ключей. измените '{$ i}' на '[$ i]' всюду. Я изначально думал о хэшах, чтобы файлы имели разную длину. – Nathan

0
#!/usr/bin/env perl 

#merging 3 - lines of first file and 3 lines of second file and next of these. 
open(F1, "<file1") or die "\ncould not find your file1\n"; 

[email protected];@lines1 = <F1> ; 

close(F1); 

open(F2, "<file2") or die "\ncould not find your file2\n"; 

[email protected];@lines2 = <F2> ; 

close(F2); 

my $value; 
my $nums; 

print "\nplease write your output file name::::\n"; 

chomp($file = <STDIN>); 

open(F3, "> $file") or die "\n could not write into your file\n"; 

$value = 0; 
foreach $nums(@lines1) { 


    if ($value % 3 == 0) { 

     print F3 $lines2[$value]; 
     print F3 $lines2[$value + 1]; 
     print F3 $lines2[$value + 2]; 

    } 
    print F3 $nums; 
    $value++; 

} 
close(F3);