4

我有大约 400'000 个文件需要替换一些文本。

我尝试了以下 Perl 脚本:

@files = <*.html>;

foreach $file (@files) {
    `perl -0777 -i -pe 's{<div[^>]+?id="user-info"[^>]*>.*?</div>}{}gsmi;' $file`;

    `perl -0777 -i -pe 's{<div[^>]+?class="generic"[^>]*>[^\s]*<small>[^\s]*Author.*?</div>.*?</div>.*?</div>.*?</div>.*?</div>}{}gsmi;' $file`;

    `perl -0777 -i -pe 's{<script[^>]+?src="javascript.*?"[^>]*>.*?</script>}{}gsmi;' $file`;

    `perl -p -i -e 's/.css.html/.css/g;' $file`;
}

我没有深入的 Perl 知识,但脚本运行速度太慢(每天只更新大约 180 个文件)。

有没有办法加快速度?

先感谢您!

PS:当我在较少数量的文件上测试它时,我注意到性能要好得多......

4

2 回答 2

8

从 perl 调用 perl 总是比在一个进程中完成所有工作要慢。所以,解决方案可能是

perl -i -pe 'BEGIN { undef $/ }
             s{<div[^>]+?id="user-info"[^>]*>.*?</div>}{}gsmi;
             s{<div[^>]+?class="generic"[^>]*>[^\s]*<small>[^\s]*Author.*?</div>.*?</div>.*?</div>.*?</div>.*?</div>}{}gsmi;
             s{<script[^>]+?src="javascript.*?"[^>]*>.*?</script>}{}gsmi;
             s/.css.html/.css/g;
    ' *.html
于 2012-11-30T21:06:14.497 回答
7

首先,如果您将 400,000 个文件名加载到内存中,那会占用一些内存。您可以轻松地遍历文件列表,例如:

  • File::Find
  • opendir+ while (readdir($dh)) (不加载整个列表)

其次,使用反引号会在 shell 中产生一个新进程,而且效率非常低。您可以正常打开文件,将它们啜饮,然后重新打印到相同的文件名。例如

while (my $file = readdir($dh)) {
    open my $fh, "<", $file or die $!;
    local $/;
    my $text = <$fh>;                # slurp file
    $text =~ s/....//g;              # do your substitutions
    open $fh, ">", $file or die $!;
    print $fh $text;                 # overwrite file, same as -i switch does
}

最后.. 使用正则表达式编辑 html 并不理想。它可能适用于您的情况,但花一些时间学习 html 解析器可能是值得的。不确定它是否适合这种特殊情况,但可能值得研究,以使您的代码更稳定。

于 2012-11-30T21:10:44.003 回答