ОБНОВЛЕНИЕ 2: решено.См. Ниже.
Я нахожусь в процессе преобразования большого txt-файла из старой библиотечной программы на базе DOS в более удобный формат.Я только начал в Perl и сумел собрать такой скрипт, как этот:
BEGIN {undef $/; };
open $in, '<', "orig.txt" or die "Can't read old file: $!";
open $out, '>', "mod.txt" or die "Can't write new file: $!";
while( <$in> )
{
$C=s/foo/bar/gm;
print "$C matches replaced.\n"
etc...
print $out $_;
}
close $out;
Это довольно быстро, но через некоторое время я всегда получаю «Out of Memory» -Error из-за нехватки RAM/ Swap-Space (у меня Win XP с 2 ГБ оперативной памяти и 1,5 ГБ Swap-файлом).После небольшого осмотра того, как работать с большими файлами, File::Map
показался мне хорошим способом избежать этой проблемы.У меня проблемы с его реализацией.Это то, что у меня есть сейчас:
#!perl -w
use strict;
use warnings;
use File::Map qw(map_file);
my $out = 'output.txt';
map_file my $map, 'input.txt', '<';
$map =~ s/foo/bar/gm;
print $out $map;
Однако я получаю следующую ошибку: Modification of a read-only value attempted at gott.pl line 8.
Кроме того, я прочитал на странице справки File::Map
, что не в Unixсистемы мне нужно использовать binmode
.Как мне это сделать?
По сути, я хочу "загрузить" файл через File :: Map, а затем запустить код, подобный следующему:
$C=s/foo/bar/gm;
print "$C matches found and replaced.\n"
$C=s/goo/far/gm;
print "$C matches found and replaced.\n"
while(m/complex_condition/gm)
{
$C=s/complex/regex/gm;
$run_counter++;
}
print "$C matches replaced. Script looped $run_counter times.\n";
etc...
Я надеюсьчто я не упустил из виду что-то слишком очевидное, но пример, приведенный на странице справки File::Map
, показывает только, как читать из сопоставленного файла, правильно?
РЕДАКТИРОВАТЬ:
Чтобы лучше проиллюстрировать то, что я в настоящее время не могу выполнить из-за нехватки памяти, приведу пример:
On http://pastebin.com/6Ehnx6xA - пример одной из наших экспортированных библиотек.записи (txt-формат).Меня интересует часть +Deskriptoren:
, начинающаяся со строки 46. Это тематические классификаторы, которые организованы в виде древовидной иерархии.
Я хочу расширить каждый классификатор своей полной цепочкой родительских узлов , но только , если ни один из родительских узлов еще не присутствует до или последочерний узел в вопросе.Это означает превращение
+Deskriptoren
-foo
-Cultural Revolution
-bar
в
+Deskriptoren
-foo
-History
-Modern History
-PRC
-Cultural Revolution
-bar
Используемое в настоящее время регулярное выражение использует Lookbehind и Lookahead, чтобы избежать дублирования дубликатов, и, следовательно, немного сложнее, чем s/foo/bar/g;
:
s/(?<=\+Deskriptoren:\n)((?:-(?!\QParent-Node\E).+\n)*)-(Child-Node_1|Child-Node_2|...|Child-Node_11)\n((?:-(?!Parent-Node).+\n)*)/${1}-Parent-Node\n-${2}\n${3}/g;
Но это работает!До тех пор, пока в Perl не кончится память, это ...: /
Так что, по сути, мне нужен способ выполнять манипуляции с большим файлом (80 МБ) в несколько строк.Время обработки не является проблемой.Вот почему я подумал о File :: Map.Другим вариантом может быть обработка файла в несколько этапов с помощью связанных perl-скриптов, вызывающих друг друга, а затем завершающихся, но я бы хотел сохранить его как можно больше в одном месте.
ОБНОВЛЕНИЕ 2:
Мне удалось заставить его работать с кодом Швельма ниже.Мой сценарий теперь вызывает следующую подпрограмму, которая вызывает две вложенные подпрограммы.Пример кода: http://pastebin.com/SQd2f8ZZ
Все еще не совсем удовлетворен тем, что я не могу заставить File::Map
работать.Ну да ладно ... Я полагаю, что линейный подход в любом случае более эффективен.
Спасибо всем!