Path :: Tiny和正则表达式替换产生空文件

时间:2018-02-17 03:15:15

标签: regex perl

我遇到了一个最糟糕的时间。我最近问过Perl Regular Expression for extracting multi-line LaTeX chapter name,并按照建议使用Perl正则表达式测试器,直到我对我的正则表达式感到满意为止。我提交了我的代码并很高兴。

但现在,当我运行程序时:

#!/usr/bin/perl -i.old     # In-place edit, backup as '.old'
use strict;
use warnings;

use Path::Tiny;

my $filename = shift or die "Usage: $0 FILENAME";
my $content = path($filename)->slurp_utf8;

$content =~ s/chapter/addchap/g;

path($filename)->spew_utf8($content);

我最终得到一个空文件。这很奇怪 - 这个替换的变体(如s/\\chapter/\\addchap/g;)因空文件而失败,但不同的替换,如$content =~ s/ //g;则不然。更奇怪的是,perl -i旗帜也没有受到尊重。到底是怎么回事?

以下是一些示例输入:

\chapter{\texorpdfstring{{I} {Into the
Primitive}}{I Into the Primitive}}

Buck did not read the newspapers, or he would have known that trouble
was brewing, not alone for himself,

我根据答案更新了我的代码,但我仍然得到空文件。

#!/usr/bin/perl
use strict;
use warnings;

use Path::Tiny;

my $filename = shift or die "Usage: $0 FILENAME";
my $content = path($filename)->slurp_utf8;

$content =~ s/\\chapter/\\addchap/gs;

path($filename)->spew_utf8($content);

我发现真正令人困惑的是,有些替换“有效”,例如:

$content =~ s/the/thee/g;

但即便

$content =~ s/ch//g;

以空文件失败。

2 个答案:

答案 0 :(得分:3)

你不希望同时拥有-i旗帜和Path :: Tiny。 -i正在将perl置于一种模式,即尝试打开并替换 你的文件。它与打开文件并自行重写不兼容。

一个选项就是删除-i标志;你的代码应该按原样运行(但它不会产生备份文件,并且文件替换不会是原子的)。

另一种方法是保留-i标志,但用

替换代码的主体
use open ':encoding(UTF-8)';
while (<>) {
    s/chapter/addchap/g;
    print;
}

(消除所有Path :: Tiny的东西)。 Perl将隐式添加其余部分。

这相当于单行

perl -CSD -i.old -pe 's/chapter/addchap/g' somefile

答案 1 :(得分:1)

脚本第一行的-i command line option可能会导致此问题。尝试删除它。

当使用perl -i调用时,Perl会在脚本周围包含一些代码,以循环遍历命令行上命名的每个文件;依次将每一行读入$_;调用你的脚本(每行一次);收集脚本打印到STDOUT的输出并将其写入临时文件;然后在最后一行之后,将临时文件重命名为原始文件的顶部。这称为“就地编辑”。

这对于1行来说特别方便,因为您不需要编写样板代码来读取文件中的输入并将输出写入文件 - 您只需编写处理代码即可。在您的情况下,您已经编写了该样板(使用Path :: Tiny),因此Perl的-i实现您的脚本正在读取输入文件并编写输出文件。由于您的脚本没有向STDOUT输出任何内容,-i将最终生成一个空文件。