2013-11-26 3 views
0

Я пишу сценарию perl, где в основном хотят открыть файл с множеством строк (одна строка в одной строке) и сравнить каждую из этих строк в другом файле (поиск файла) и печать каждого вхождения этого. Я написал следующий код для одной конкретной строки найти. Как я могу улучшить его для списка строк из файла.Поиск группы строк в файле присутствует в другом файле или нет

open(DATA, "<filetosearch.txt") or die "Couldn't open file filetosearch.txt for reading: $!"; 
my $find = "word or string to find"; 
#open FILE, "<signatures.txt"; 
my @lines = <DATA>; 
print "Lined that matched $find\n"; 
for (@lines) { 
    if ($_ =~ /$find/) { 
     print "$_\n"; 
    } 
} 
+0

Будут ли строки из любого файла помещается в памяти все сразу? – woolstar

+0

Вы открываете файл filetosearch.txt для записи, а не чтения. – woolstar

+0

Да, файлы имеют около 500 строк и помещаются в память. Хорошо, я должен исправить файл filetosearch.txt, чтобы читать только как: open (DATA, " Sharath

ответ

0

Ok, что-то вроде это будет быстрее.

sub testmatch 
{ 
    my ($find, $linesref)= @_ ; 

    for (@$linesref) { if ($_ =~ /$find/) { return 1 ; } } 
    return 0 ; 
} 

{ 
    open(DATA, "<filetosearch.txt") or die "die" ; 
    my @lines = <DATA> ; 

    open(SRC, "tests.txt") ; 
    while (<SRC>) 
    { 
    if (testmatch($_, \@lines)) { print "a match\n" } 
    } 
} 

Если его соответствие полной линии к полной линии, лет и можно упаковать одну строку в качестве ключа к хэш и просто тест существования:

{ 
    open(DATA, "<filetosearch.txt") or die "die" ; 
    my %lines ; 
    @lines{<DATA>}= undef ; 

    open(SRC, "tests.txt") ; 
    while (<SRC>) 
    { 
    if ($_ ~~ %lines) { print "a match\n" } 
    } 
} 
+1

Всегда и не обязательно 'use strict; использовать предупреждения; '. – Kenosis

+0

Фактически я просто использую 5.012; – woolstar

+0

Большое спасибо Woolstar. Но я забыл включить, что я хотел напечатать 3 строки раньше, из шаблона соответствия. Как мне это сделать? – Sharath

0

Вот еще один вариант:

use strict; 
use warnings; 

my $searchFile = pop; 
my @strings = map { chomp; "\Q$_\E" } <>; 
my $regex  = '(?:' . (join '|', @strings) . ')'; 

push @ARGV, $searchFile; 

while (<>) { 
    print if /$regex/; 
} 

Использование: perl script.pl strings.txt searchFile.txt [>outFile.txt]

Последний, необязательный параметр направляет вывод файл.

Во-первых, имя файла поиска (неявно) pop отключено @ARGV и сохранено для последующего использования. Затем считывается файл строк (<>), а map используется для линии chomp каждой линии, выбегают метасимволы (\Q и \E, если могут быть символы регулярных выражений, например, «.» Или «*» и т. Д. в строке), то эти строки передаются в массив. Элементы массива: join ed с символом чередования регулярных выражений (|), чтобы эффективно сформировать оператор OR всех строк, которые будут сопоставляться с каждой строкой файла поиска. Затем имя файла поиска: push ed на @ARGV, чтобы его строки можно было искать. Опять же, каждая строка имеет значение chomp ed и print ed, если одна из строк найдена на линии.

Надеюсь, это поможет!

1

Я хотел бы попробовать что-то вроде этого:

use strict; 
use warnings; 
use Tie::File; 

tie my @lines, 'Tie::File', 'filetosearch.txt'; 
my @matched; 
my @result; 
tie my @patterns, 'Tie::File', 'patterns.txt'; 
foreach my $pattern (@patterns) 
{ 
    $pattern = quotemeta $pattern; 
    @matched = grep { /$pattern/ } @lines; 
    push @result, @matched; 
} 
  • я использую Tie :: Файл, потому что это удобно (не особенно в этом случае, но другие), другие (возможно, много других ?) не согласятся, но это не имеет значения здесь
  • Grep является основной функцией, что очень хорошо, что он делает (по моему опыту)
+1

+1 для предложения с использованием 'Tie :: File' для этого случая. Это может быть * заведомо медленным * с большими файлами, но OP не имеет отношения к такому. Рассмотрим '/ \ Q $ pattern \ E /', поскольку в строках могут быть метасимволы. – Kenosis

+0

@ Кенозис Спасибо, Кенозис, я добавил ваше предложение. Лично я предпочитаю использовать quotemeta, поскольку я думаю, что это улучшает читаемость. –

+0

Добро пожаловать! Ваша точка читаемости имеет смысл. Вы могли бы, конечно, '$ pattern = quotemeta $ pattern;' перед 'grep'ping. – Kenosis

0

может быть что-то, как это будет делать работу:

open FILE1, "filetosearch.txt"; 
my @arrFileToSearch = <FILE1>; 
close FILE1; 

open FILE2, "signatures.txt"; 
my @arrSignatures = <FILE2>; 
close FILE2; 

for(my $i = 0; defined($arrFileToSearch[$i]);$i++){ 
    foreach my $signature(@arrSignatures){ 
     chomp($signature); 
     $signature = quotemeta($signature);#to be sure you are escaping special characters 
     if($arrFileToSearch[$i] =~ /$signature/){ 
      print $arrFileToSearch[$i-3];#or any other index that you want 
     } 
    } 

}

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