如何在 Perl 中将命令行参数视为 UTF-8?
Posted
技术标签:
【中文标题】如何在 Perl 中将命令行参数视为 UTF-8?【英文标题】:How can I treat command-line arguments as UTF-8 in Perl? 【发布时间】:2011-01-03 11:51:30 【问题描述】:如何在 Perl 中将 @ARGV
的元素视为 UTF-8?
目前我正在使用以下解决方法..
use Encode qw(decode encode);
my $foo = $ARGV[0];
$foo = decode("utf-8", $foo);
.. 有效但不是很优雅。
我正在使用从 bash v3.2.25 调用的 Perl v5.8.8,LANG 设置为 en_US.UTF-8。
【问题讨论】:
只是一个微妙的细节:ARGV 本身通常表示名为 ARGV 的文件句柄。对于保存命令行参数的数组@ARGV,答案有点不同。 :) 【参考方案1】:外部数据源在 Perl 中很棘手。对于命令行参数,您可能会将它们作为您的语言环境中指定的编码。不要依赖您的语言环境与可能运行您的程序的其他人相同。
你必须找出是什么然后转换成 Perl 的内部格式。幸运的是,这并不难。
I18N::Langinfo 模块包含获取编码所需的内容:
use I18N::Langinfo qw(langinfo CODESET);
my $codeset = langinfo(CODESET);
一旦知道编码,就可以将它们解码为 Perl 字符串:
use Encode qw(decode);
@ARGV = map decode $codeset, $_ @ARGV;
虽然 Perl 将内部字符串编码为 UTF-8,但您永远不应该考虑或知道这一点。你只需解码你得到的任何东西,这会将它变成 Perl 的内部表示。相信 Perl 会处理所有其他事情。当您需要存储数据时,请确保使用您喜欢的编码。
如果你知道你的设置是 UTF-8 并且终端会给你作为 UTF-8 的命令行参数,你可以使用 A
选项和 Perl 的 -C
开关。这告诉您的程序假设参数被编码为 UTF-8:
% perl -CA program
【讨论】:
我对这个答案的问题是 I18N::Langinfo 在 Win32 上不可用(即使它在 corelist 中!)。 我的 perl (5.18.0, Mac OS X 10.8) 在 $codeset 中返回 US-ASCII,即使我的终端设置为 unicode(UTF-8)。如果我手动将 $codeset 设置为 UTF-8,则 decode() 可以工作。 这会在 v5.18 和 X.8 中为我返回UTF-8
:$ perl5.18.0 -MI18N::Langinfo=langinfo,CODESET -E 'say langinfo( CODESET )'
。你确定你的东西设置正确吗?【参考方案2】:
使用Encode::Locale:
use Encode::Locale;
decode_argv Encode::FB_CROAK;
这在 Win32 上也有效,对我来说还不错。
【讨论】:
你在哪个版本的 perl 中找到Encode::Locale
?我有 v5.10.1,尝试use Encode::Locale
会导致找不到模块。 :(
它不在核心中,你可以从 cpan 或你的包管理器中安装它。
在我的情况下decode_argv
默认不导入,所以use Encode::Locale qw(decode_argv);
是必需的。【参考方案3】:
例如对于窗户 设置代码
chcp 1251
在 perl 中:
use utf8;
use Modern::Perl;
use Encode::Locale qw(decode_argv);
if (-t)
binmode(STDIN, ":encoding(console_in)");
binmode(STDOUT, ":encoding(console_out)");
binmode(STDERR, ":encoding(console_out)");
Encode::Locale::decode_argv();
在命令行中
perl -C ppixregexplain.pl qr/\bмама\b/i > ex1.html 2>&1
在哪里ppixregexplain.pl
【讨论】:
【参考方案4】:您的做法似乎是正确的。这就是我会做的。
但是,这个perldoc page 建议命令行标志-CA
应该告诉它将@ARGV
视为utf-8。 (未测试)。
【讨论】:
-CA 期望将命令行参数编码为 UTF-8。这并不意味着他们是。 :) 感谢您的信息,所以您说这种方式假定 UTF-8 编码,但您的方式会发现编码...? 我发现假设任何编码都不安全。太多人让它在他们的机器上工作,然后发现它被其他设置不同的人破坏。 请注意,这在脚本中不起作用,即您不能执行#!/usr/bin/perl -CA
。或者至少我下载的脚本失败了。【参考方案5】:
你不应该对字符串做任何特别的事情。 Perl 字符串从 Perl 5.8 开始默认为 UTF-8。
perl -CO -le 'print "\x2603"' | xargs perl -le 'print "I saw @ARGV"'
上面的代码在 Ubuntu 9.04、OS X 10.6 和 FreeBSD 7 上运行良好。
FalseVinylShrub 提出了一个很好的观点,我们可以看到两者之间的明显区别
perl -Mutf8 -wle ';print utf8::is_utf8($ARGV[0]) ? "t" : "f"' a
和
perl -Mutf8 -CA -wle ';print utf8::is_utf8($ARGV[0]) ? "t" : "f"' a
【讨论】:
不过,命令行参数不会以 Perl 字符串的形式开始。它是一个与其他任何东西一样的外部数据源。 但如果他或她的 shell 设置为 UTF-8,那么他或她输入的任何内容都将是 UTF-8。 我发现指定工作环境比尝试覆盖所有可能的环境更容易。现在,如果这是为了分发给其他人,那会改变一些事情,但问题包括终端将设置为 UTF-8 的事实。同样,大多数时候我不会乱用File::Spec
,即使我的代码无法在某些系统上运行。以上是关于如何在 Perl 中将命令行参数视为 UTF-8?的主要内容,如果未能解决你的问题,请参考以下文章