如何在 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?的主要内容,如果未能解决你的问题,请参考以下文章

在perl中将文件添加到压缩文件夹

如何在不使用命令行的情况下运行 Perl 脚本?

在 Perl 中,如何在命令行上发送 CGI 参数?

如何让 perl 正确传递具有多个参数和复杂文件路径(空格和符号)的命令行参数?

命令行应用程序 Web 前端的推荐通信模式

如何将强制和可选命令行参数传递给 perl 脚本?