在命令行选项上有条件地将perl中的默认编码设置为utf-8

在命令行选项上有条件地将perl中的默认编码设置为utf-8,perl,encoding,utf-8,Perl,Encoding,Utf 8,为了在Perl中处理utf-8中的文本,我一直在使用binmode(,“:encoding(utf-8)”在我使用的每个流上。我刚刚发现 use open ( ":encoding(UTF-8)", ":std" ); 可以用来在全球范围内做同样的事情。这很好,因为这意味着重复代码要少得多 但是现在我遇到了一个问题:我想在我的脚本中有一个命令行选项,-utf8,它只在提供时才将所有内容转换为utf-8。由于use open是一个pragma,它在词汇上是有范围的,我不能将它放在if语句中,但如

为了在Perl中处理utf-8中的文本,我一直在使用
binmode(,“:encoding(utf-8)”在我使用的每个流上。我刚刚发现

use open ( ":encoding(UTF-8)", ":std" );
可以用来在全球范围内做同样的事情。这很好,因为这意味着重复代码要少得多

但是现在我遇到了一个问题:我想在我的脚本中有一个命令行选项,
-utf8
,它只在提供时才将所有内容转换为utf-8。由于
use open
是一个pragma,它在词汇上是有范围的,我不能将它放在if语句中,但如果没有if语句,它就不能依赖于命令行选项

下面是一个简单的例子来说明这个问题,称之为problem.pl

#/usr/bin/env perl
#在我的最小示例中是硬编码的,通常由命令行选项-utf8设置
我的$use\u utf8=1;
#use仅适用于其词法范围-这不起作用
如果($use_utf8){
使用open(“:encoding(UTF-8)”,“:std”);
}
#如果我把它放在正确的词法范围内,它并不以$use\u utf8为条件
#…e打开(“:编码(UTF-8)”,“:标准”);
而(){
打印长度(美元);
}
当我在一个文件上运行此代码时,调用
input
,其中包含一行2字节UTF-8字符,比如
a
,它输出3:

$ ./problem.pl input
3
如果我将
use open
语句移动到全局范围,我将得到长度为2(一个字符加一个换行符)的预期结果:

那么,我如何全局地将编码设置为utf-8,但在命令行选项上有条件地设置,这样我就可以使用
-utf8
得到2,而不使用utf-8得到3

另外,在我的实际用例中,我使用spaceship操作符(
while()
)在命令行语法中提供了处理多个文件的高度灵活性,但在这种情况下,我不能调用
binmode
,因为文件句柄是由Perl自动管理的<代码>使用open
将是一个更好的选择,如果我能使它有条件的话

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

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

该选项的工作原理类似于utf8层的open杂注<代码>-CSD将在标准手柄和任何打开的手柄(D)上进行设置。不幸的是,它使用了不太安全的
:utf8
层,而不是
:encoding(UTF-8)
,因此如果您将其用于实际不是UTF-8的输入,则可能会导致字符串中断。另外,
-CD
为整个程序中打开的任何句柄设置默认值,而不仅仅是脚本的词法范围,这可能会中断不需要的模块的使用。(
-CS
始终是全局的,开放pragma的“:std”效果也是全局的,因为标准句柄是全局的。)


很酷,很好用。我从未想过在BEGIN块中进行命令行解析,但它是有效的,所以为什么不呢。这意味着在BEGIN块之外而不是像在my
GetOptions()
中一样为我的选项声明变量,但这是一个很容易修复的细节。今天我刚刚学习了
使用if…
语法。关于
-C
:除了不太安全的
:utf8
,我真的不喜欢用
perl显式调用我的脚本。。。脚本名称
,因此您的第一个解决方案是我目前首选的解决方案。在我的研究中,我确实发现了关于
-C
,我认为当我想暂时使脚本utf8友好而不修改它时,这是一个值得记住的选项。@joanis,这是因为
使用
和词法范围都是编译时的概念。
$ ./problem.pl input
2
my $use_utf8;
BEGIN { $use_utf8 = 1; }
use if $use_utf8, 'open', ':std', ':encoding(UTF-8)';
perl -CSD problem.pl input