2014-08-30 2 views
0

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

Я пробовал столько вариаций, о которых я мог думать, и никто не работает. Этот конкретный код, который я публикую, считает, что каждый элемент в массиве отличается от того, который находится в другом массиве.

use 5.18.2; 
use strict; 
use utf8; 

printf "This program only compares two files.\n" 
    . "Here are the differences between " 
    . $ARGV[0] . " and " . $ARGV[1] . ":\n"; 

open FIRST_FH, '<', $ARGV[0]; 

chomp(my @file1 = <FIRST_FH>); 

close FIRST_FH; 
open SECOND_FH, '<', $ARGV[1]; 

chomp(my @file2 = <SECOND_FH>); 

close SECOND_FH; 
for(my $i=0; $i < scalar @file1; ++$i){ 
    my $string = $file2[$i]; 
    unless($_ =~ /$string/){ 
    print "Difference found: @file1[$i], @file2[$i]\n"; 
    } 
} 

ответ

0

Почему вы сравниваете использование $_? Что вы нигде не определили?

my $string = $file2[$i]; 
unless($_ =~ /$string/){ 

Просто сравните линии с помощью eq или ne:

if ($file1[$i] ne $file2[$i]) { 

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

use 5.18.2; 
use strict; 
use warnings; 
use autodie; 
use utf8; 

my ($file1, $file2) = @ARGV; 

open my $fh1, '<', $file1; 
open my $fh2, '<', $file2; 

while (!eof($fh1) && !eof($fh2)) { 
    chomp(my $line1 = <$fh1>); 
    chomp(my $line2 = <$fh2>); 
    if (line1 ne $line2) { 
     warn "Difference found on line $.:\n $line1\n $line2\n"; 
    } 
} 

warn "Still more data in $file1\n" if !eof $fh1; 
warn "Still more data in $file2\n" if !eof $fh2; 
+0

Я полностью забыл об эквалайзерах и ne, хотя я узнал о них. Спасибо за правильное направление. – banana

1

use utf8; просто инструктирует переводчика, чтобы прочитать исходный файл в UTF-8. Используйте прагму open для установки уровней IO по умолчанию для UTF-8 (или вручную укажите «<: кодирование (UTF-8)» в качестве второго аргумента open).

Не используйте printf, когда print будет достаточным (как правило, из-за интерполяции). В этом конкретном случае я считаю, что heredoc является наиболее читаемым.

Неэффективно считывать оба файла в память. Итерируйте их лениво, взяв по одной строке за один раз в цикле while.

Всегда проверяйте, не удалось ли open и включить в сообщение об ошибке $!. Альтернативно, use autodie;, который обрабатывает это для вас. Кроме того, используйте лексические дескрипторы файлов; они автоматически закрываются, когда они выходят за пределы области видимости, и не будут сталкиваться с другими головоломками (например, подпрограммами и встроенными функциями).

Имея в виду эти предложения, новый код будет выглядеть следующим образом:

#!/usr/bin/perl 
use 5.18.2; # Implicitly loads strict 
use warnings; 
use open qw(:encoding(utf8) :std); 

print <<"EOT"; 
This program only compares 2 files. 
Here are the differences between 
$ARGV[0] and $ARGV[1]: 
EOT 

open(my $file1, '<', shift) or die $!; 
open(my $file2, '<', shift) or die $!; 

while (my $f1_line = <$file1>, my $f2_line = <$file2>) 
{ 
    if ($f1_line ne $f2_line) 
    { 
     print $f1_line, $f2_line; 
    } 
} 

Но это еще наивный алгоритм; если один файл имеет удаленную строку, все последующие строки будут отличаться между файлами. Чтобы правильно достичь сравнения diff, вам понадобится реализация алгоритма, который найдет самую длинную общую подпоследовательность. Рассмотрите возможность использования модуля CPAN Algorithm::Diff.

Смежные вопросы