Сравнение строк в файле с perl

Я пытался сравнить строки между двумя файлами и совпадающими строками, которые одинаковы.

По какой-то причине приведенный ниже код всегда проходит только первую строку «text1.txt» и печатает оператор «if» независимо от того, совпадают ли две переменные или нет.

Спасибо

use strict;
open( <FILE1>, "<text1.txt" );
open( <FILE2>, "<text2.txt" );
foreach my $first_file (<FILE1>) {
    foreach my $second_file (<FILE2>) {
        if ( $second_file == $first_file ) {
            print "Got a match - $second_file + $first_file";
        }
    }
}
close(FILE1);
close(FILE2);

person kristin    schedule 10.03.2011    source источник


Ответы (7)


Если вы сравниваете строки, используйте оператор eq. "==" сравнивает аргументы численно.

person Eugene Yarmash    schedule 10.03.2011

Вот способ выполнить эту работу, если ваши файлы не слишком велики.

#!/usr/bin/perl
use Modern::Perl;
use File::Slurp qw(slurp);
use Array::Utils qw(:all);
use Data::Dumper;

# read entire files into arrays
my @file1 = slurp('file1');
my @file2 = slurp('file2');

# get the common lines from the 2 files
my @intersect = intersect(@file1, @file2);

say Dumper \@intersect;
person Toto    schedule 10.03.2011

Лучшим и более быстрым (но менее эффективным с точки зрения использования памяти) подходом было бы чтение одного файла в хэш, а затем поиск строк в хеш-таблице. Таким образом, вы просматриваете каждый файл только один раз.

# This will find matching lines in two files,
# print the matching line and it's line number in each file.

use strict;

open (FILE1, "<text1.txt") or die "can't open file text1.txt\n";
my %file_1_hash;
my $line;
my $line_counter = 0;

#read the 1st file into a hash 
while ($line=<FILE1>){
  chomp ($line); #-only if you want to get rid of 'endl' sign
  $line_counter++;
  if (!($line =~ m/^\s*$/)){
    $file_1_hash{$line}=$line_counter;
  }
}
close (FILE1);

#read and compare the second file
open (FILE2,"<text2.txt") or die "can't open file text2.txt\n";
$line_counter = 0;
while ($line=<FILE2>){
  $line_counter++;
  chomp ($line);
  if (defined $file_1_hash{$line}){
    print "Got a match: \"$line\"
in line #$line_counter in text2.txt and line #$file_1_hash{$line} at text1.txt\n";
  }
}
close (FILE2);
person SIMEL    schedule 10.03.2011

Вы должны повторно открыть или сбросить указатель файла 2. Переместите команды open и close внутрь цикла.

Более эффективный способ сделать это, в зависимости от размера файла и строки, состоял бы в том, чтобы перебирать файлы только один раз и сохранять каждую строку, которая встречается в файле 1, в хеше. Затем проверьте, была ли строка для каждой строки в файле 2.

person Tim    schedule 10.03.2011

Если вы хотите количество строк,

my $count=`grep -f [FILE1PATH] -c [FILE2PATH]`;

Если вам нужны совпадающие строки,

my @lines=`grep -f [FILE1PATH]  [FILE2PATH]`;

Если вам нужны строки, которые не совпадают,

my @lines = `grep -f [FILE1PATH] -v [FILE2PATH]`;
person Azheid    schedule 09.01.2012

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


use warnings;

open (FILE, "orig.txt") or die "Unable to open first file.\n"; @data1 = ; close(FILE);

open (FILE, "2.txt") or die "Unable to open second file.\n"; @data2 = ; close(FILE);

for($i = 0; $i < @data1; $i++){ $data1[$i] =~ s/\s+$//; $data2[$i] =~ s/\s+$//; if ($data1[$i] ne $data2[$i]){ print "Failure to match at line ". ($i + 1) . "\n"; print $data1[$i]; print "Doesn't match:\n"; print $data2[$i]; print "\nProgram Aborted!\n"; exit; } }

print "\nThe files are identical. \n";

person Cooper    schedule 10.03.2011

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

use strict;
use warnings;
use autodie;

open my $fh1, '<', 'text1.txt';
open my $fh2, '<', 'text2.txt';

while(
  defined( my $line1 = <$fh1> )
  and
  defined( my $line2 = <$fh2> )
){
  chomp $line1;
  chomp $line2;

  if( $line1 eq $line2 ){
    print "Got a match - $line1\n";
  }else{
    print "Lines don't match $line1 $line2"
  }
}

close $fh1;
close $fh2;

Теперь то, что вам действительно может понадобиться, — это сравнение двух файлов, которое лучше оставить для Text: : Дифф.

use strict;
use warnings;

use Text::Diff;

print diff 'text1.txt', 'text2.txt';
person Brad Gilbert    schedule 10.03.2011