【问题标题】:Setting default encoding to utf-8 in perl conditionally on command-line option在命令行选项有条件地在 perl 中将默认编码设置为 utf-8
【发布时间】: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 (&lt;&gt;)) 来提供命令行语法的高度灵活性来处理多个文件,但在这种情况下我不能调用 binmode,因为文件句柄由 Perl 自动管理。 use open 将是一个更好的选择,如果我可以使其成为有条件的。

PS:是的,我确实仍然有非 utf8 数据希望继续处理。感谢上帝,我们的大部分数据现在都是 utf-8 格式,但不幸的是还不是全部。

【问题讨论】:

    标签: perl encoding utf-8


    【解决方案1】:

    首先:您可以使用if 有条件地应用词法杂注。只需确保条件在编译时可用(之前可能需要使用 BEGIN 块)。

    my $use_utf8;
    BEGIN { $use_utf8 = 1; }
    use if $use_utf8, 'open', ':std', ':encoding(UTF-8)';
    

    -C 选项的作用类似于 utf8 层的 open pragma。 -CSD 将在标准句柄 (S) 和任何打开的句柄 (D) 上设置它。不幸的是,它使用不太安全的:utf8 层而不是:encoding(UTF-8),因此如果您将它用于实际上不是UTF-8 的输入,您最终可能会收到损坏的字符串。此外,-CD 为在整个程序中打开的任何句柄设置默认值,而不仅仅是脚本的词法范围,这可能会破坏不期望的模块的使用。 (-CS 总是全局的,就像 open pragma 的 ':std' 效果一样,因为标准句柄是全局的。)

    perl -CSD problem.pl input
    

    【讨论】:

    • 酷,很好用。我从来没有想过在 BEGIN 块中进行命令行解析,但它有效,所以为什么不呢。这意味着在 BEGIN 块之外而不是在我的 GetOptions() 内声明我的选项的变量,但这是一个很容易修复的细节。我今天刚学会use if... 语法。
    • 关于-C:除了不太安全的:utf8,我真的很讨厌用perl ... script name 明确地调用我的脚本,所以到目前为止,您的第一个解决方案是我的首选。我确实在我的研究中发现了 -C,我认为当我想暂时使脚本 utf8 友好而不修改它时,我认为这是一个值得记住的选项。
    • @joanis 这是因为use 和词法范围都是编译时概念。
    猜你喜欢
    • 2012-03-10
    • 2012-02-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-07
    • 2010-10-17
    • 1970-01-01
    • 2014-04-19
    • 2013-11-15
    相关资源
    最近更新 更多