【发布时间】:2019-07-19 22:04:21
【问题描述】:
为了在 Perl 中处理 utf-8 格式的文本,我一直在我使用的每个流上使用 binmode(<file-handle>, ":encoding(UTF-8)");。我才发现
use open ( ":encoding(UTF-8)", ":std" );
可以用来在全局范围内做同样的事情。这很棒,因为这意味着更少的重复代码。
但现在我有一个问题:我想为我的脚本添加一个命令行选项-utf8,它仅在提供时将所有内容转换为 utf-8。由于use open 是一个编译指示,它是词法范围的,我不能将它放在 if 语句中,但如果没有 if 语句,它就不能依赖命令行选项。
这是一个说明问题的最小示例,称之为问题.pl
#!/usr/bin/env perl
# hard-coded in my minimal example, normally set by command line option -utf8
my $use_utf8 = 1;
# use only applies within its lexical scope - this does not work
if ($use_utf8) {
use open ( ":encoding(UTF-8)", ":std" );
}
# if I put it at the right lexical scope, it's not conditional on $use_utf8
#..e open ( ":encoding(UTF-8)", ":std" );
while (<>) {
print length($_);
}
当我在文件上运行此代码时,调用 input,其中包含一行带有 2 字节 UTF-8 字符的行,例如 à,它会输出 3:
$ ./problem.pl input
3
如果我将 use open 语句移动到全局范围,我会得到长度为 2(一个字符加一个换行符)的预期结果:
$ ./problem.pl input
2
那么我怎样才能在全局范围内将编码设置为 utf-8,但有条件地使用命令行选项,这样我会得到 2 和 -utf8 但没有 3。
另外,在我的实际用例中,我使用了 spaceship 运算符 (while (<>)) 来提供命令行语法的高度灵活性来处理多个文件,但在这种情况下我不能调用 binmode,因为文件句柄由 Perl 自动管理。 use open 将是一个更好的选择,如果我可以使其成为有条件的。
PS:是的,我确实仍然有非 utf8 数据希望继续处理。感谢上帝,我们的大部分数据现在都是 utf-8 格式,但不幸的是还不是全部。
【问题讨论】: