Подставляя миллионы регулярных выражений (perl) - PullRequest
0 голосов
/ 19 сентября 2018

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

use strict;
use warnings;

my $filename = 'names.txt';

my $data = read_file($filename);

$data =~ s/88tx0p/Author1/g;
##and then there are 1,000,000+ other substitution regexes.

write_file($filename, $data);
exit;

sub read_file {
my ($filename) = @_;

open my $in, '<:encoding(UTF-8)', $filename or die "Could not open 
'$filename' for reading $!";
local $/ = undef;
my $all = <$in>;
close $in;

return $all;
}

sub write_file {
my ($filename, $content) = @_;

open my $out, '>:encoding(UTF-8)', $filename or die "Could not open 
'$filename' for writing $!";;
print $out $content;
close $out;

return;
}

Но потом я понял, что этот скрипт пытается записать вывод в исходный файл, который, как я полагаю, использует больше памяти?Поэтому я попробовал следующее:

use strict;
use utf8;
use warnings;

open(FILE, 'names.txt') || die "File not found";
my @lines = <FILE>;
close(FILE);

my @newlines;
foreach(@lines) {
$_ =~ s/88tx0p/Author1/g;
##and then there are approximately 1,000,000 other substitution regexes.
push(@newlines,$_);
}

open(FILE, '>names_edited.txt') || die "File not found";
;
print FILE @newlines;
close(FILE);

Но опять же, это заняло слишком много памяти.Могу ли я получить помощь по способам сделать это, используя минимальный объем памяти?Спасибо всем.

1 Ответ

0 голосов
/ 19 сентября 2018

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

Попробуйте это в цикле while:

open ( my $file, '<', 'names.txt' ) or die $!; 
open ( my $output, '>', 'names_edited.txt' ) or die $!;
select $output; #destination for print; 
while ( <$file> ) {  #reads one line at a time, sets $_
    s/88tx0p/Author1/g;   #acts on $_ by default
    print; #defaults to printing $_ to the selected filehandle $output
}

Это будет работать построчно (какваш первоначальный код был), но будет читать только одну строку за раз, поэтому объем памяти будет значительно ниже.

...