有条件地在命令行选项

时间:2019-07-19 22:04:21

标签: perl encoding utf-8

为了在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,但有条件地在命令行选项上使用,这样我在使用-utf8时将获得2,​​而在没有while (<>)时将获得3。

此外,在我的实际用例中,我使用太空飞船运算符(binmode)在命令行语法中提供了高度灵活性,以处理多个文件,但是在这种情况下,我无法调用{{1} },因为文件句柄由Perl自动管理。如果可以有条件的话,use open将是一个更好的选择。

PS:是的,我确实确实还有我想继续处理的非utf8数据。谢天谢地,我们大多数数据现在都保存在utf-8中,但不幸的是还不是全部。

1 个答案:

答案 0 :(得分:1)

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

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

-C选项的工作方式类似于utf8层的打开编译指示。 -CSD会将其设置在标准手柄(S)和任何打开的手柄(D)上。不幸的是,它使用的是不太安全的:utf8层而不是:encoding(UTF-8),因此如果将其用于实际上不是UTF-8的输入,则可能会导致字符串损坏。另外,-CD为整个程序中打开的所有句柄设置默认值,而不仅仅是脚本的词法范围,这可能会中断不需要它的模块的使用。 (-CS始终是全局的,开放式编译指示的':std'效果也是如此,因为标准句柄是全局的。)

perl -CSD problem.pl input