更新 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;
它非常快,但一段时间后我总是收到“内存不足”-由于缺少 RAM/交换空间而导致的错误(我在 Win XP 上使用 2GB 内存和 1.5GB 交换文件)。在环顾了一下如何处理大文件之后,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
帮助页面上给出的示例仅显示了如何从映射文件中读取,对吗?
编辑:
为了更好地说明我目前由于内存不足而无法完成的事情,我将举一个例子:
在http://pastebin.com/6Ehnx6xA上是我们导出的图书馆记录之一的样本(txt 格式)。我对+Deskriptoren:
从第 46 行开始的部分感兴趣。这些是主题分类器,按树形层次结构组织。
我想要的是用其完整的父节点链扩展每个分类器,但前提是在所讨论的子节点之前或之后没有父节点不存在。这意味着转
+Deskriptoren
-foo
-Cultural Revolution
-bar
进入
+Deskriptoren
-foo
-History
-Modern History
-PRC
-Cultural Revolution
-bar
当前使用的 Regex 使用 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 的内存用完... :/
所以本质上我需要一种方法来对一个大文件(80MB)进行多行操作。处理时间不是问题。这就是我想到 File::Map 的原因。另一种选择可能是分几个步骤处理文件,链接的 perl 脚本相互调用然后终止,但我想尽可能地将它保存在一个地方。
更新 2:
我设法让它与下面的 Schwelm 代码一起工作。我的脚本现在调用以下子例程,该子例程调用两个嵌套子例程。示例代码位于: http: //pastebin.com/SQd2f8ZZ
仍然不太满意,因为我不能File::Map
上班。哦,好吧...我想无论如何,线路方法更有效。
感谢大家!