以下简单脚本(基本上)在其输入中徘徊,根据正则表达式对其进行拆分,替换结果列表中每个元素中的所有换行符,并逐个打印出已修改的元素:
# demo.pl
use strict;
use utf8;
use open qw(:std :utf8);
use warnings qw(FATAL utf8);
BEGIN { $/ = $\ = undef; }
while ( <> ) {
s/\n\z//;
s/\n/\\n/g, print "$_\n" for split /\n(?=[^\W\d]\w*=)/;
}
给定输入文件(INPUTFILE
)并将以下(UTF8编码)内容作为其参数
A=42
ΦΡΩΒΩΖΖ=ABCDEFGHIJKLMNOPQRSTUVWXYZ
_B_C_D12=
foo
345bar=nope
baz
=whatever=
X_Y_Z=quux
...它打印出所需的输出,即:
% perl demo.pl INPUTFILE
A=42
ΦΡΩΒΩΖΖ=ABCDEFGHIJKLMNOPQRSTUVWXYZ
_B_C_D12=\nfoo\n345bar=nope\nbaz\n =whatever=
X_Y_Z=quux
相比之下,以下几乎相同的CLI单行
% perl -ne 'use strict; use utf8; use open qw(:std :utf8); use warnings qw(FATAL utf8); BEGIN { $/ = $\ = undef; } s/\n\z//; s/\n/\\n/g, print "$_\n" for split /\n(?=[^\W\d]\w*=)/;' INPUTFILE
...为相同的输入文件生成以下内容
A=42\nΦΡΩÎΩÎÎ=ABCDEFGHIJKLMNOPQRSTUVWXYZ
_B_C_D12=\nfoo\n345bar=nope\nbaz\n =whatever=
X_Y_Z=quux
这里有(显然)两个问题:
(我希望这两个问题都有相同的根本原因。)
“文件内脚本”(demo.pl
)和CLI单行之间的唯一区别是前者用while ( <> ) { ... }
显式包装脚本的主体,而对于后者, -n
标志会自动插入此包装器。
问:如何修改上面的单行,以便使用-n
标记生成所需的结果?
BTW,毫不奇怪,完全命令行等效于demo.pl
(没有-n
标志),即
% perl -e 'use strict; use utf8; use open qw(:std :utf8); use warnings qw(FATAL utf8); BEGIN { $/ = $\ = undef; } while ( <> ) { s/\n\z//; s/\n/\\n/g, print "$_\n" for split /\n(?=[^\W\d]\w*=)/; }' INPUTFILE
也会产生所需的输出。
所以问题,无论是什么,都与-n
标志有关。
FWIW:
% perl -v | head -2
This is perl 5, version 20, subversion 2 (v5.20.2) built for x86_64-linux-gnu-thread-multi
编辑:还有一条线索:如果失败的一行内容的输入是通过STDIN
传递而不是@ARGV
中的文件名(例如将INPUTFILE
替换为< INPUTFILE
}),然后它产生所需的输出完全清晰,虽然仍然不正确,输出:
A=42\nΦΡΩΒΩΖΖ=ABCDEFGHIJKLMNOPQRSTUVWXYZ
_B_C_D12=\nfoo\n345bar=nope\nbaz\n =whatever=
X_Y_Z=quux
我目前的猜测是,use open qw(:std :utf8)
未涵盖<>
在@ARGV
中作为文件名传递输入时读取的输入流。
答案 0 :(得分:3)
“文件内脚本”(demo.pl)和CLI单行之间的唯一区别是前者用while(&lt;&gt;){...}显式包装脚本的主体,而对于后者,-n标志会自动插入此包装器。
是的,确切地说 - -n
将所有代码包裹在while (<>) { ... }
中。这包括您的use utf8;
和use open(:utf8);
行,因此在启用Unicode 时文件已经打开。
您可以通过运行-n
版本的等效程序轻松验证这一点:
while (<>) {
# demo.pl
use strict;
use utf8;
use open qw(:std :utf8);
use warnings qw(FATAL utf8);
BEGIN { $/ = $\ = undef; }
s/\n\z//;
s/\n/\\n/g, print "$_\n" for split /\n(?=[^\W\d]\w*=)/;
}
并看到同样的效果。
更有趣的是,您可以看到use
声明仍然有效:通过两次运行完全相同的输入文件
perl demo.pl INPUTFILE INPUTFILE
你得到两个输出,第一个输出,第二个输出正确。你的单行也会发生这种情况。
您可以使用-C
flag with the i
(8)选项默认启用UTF-8输入:
perl -CiO -ne 'use strict; use utf8; BEGIN { $/ = $\ = undef; } s/\n\z//; s/\n/\\n/g, print "$_\n" for split /\n(?=[^\W\d]\w*=)/;' INPUTFILE
确保在打开文件之前启用UTF-8,并获得正确的输出。 O
也可以为标准输出启用UTF-8,以便您可以打印它。