为什么我的 Perl 不能很好地处理 Unicode?

为什么我的 Perl 不能很好地处理 Unicode?

在我新安装的 Arch 上,perlUnicode 似乎不太好用。例如,给定以下输入文件:

ελα ρε
王小红

这个命令应该给我每行的最后两个字符:

$ perl -CIO -pe 's/.*(..)$/$1/' file
ε
º¢

然而,正如你在上面看到的,我得到了胡言乱语。正确的输出是:

ρε
小红

我知道我的终端 ( gnome-terminator) 支持 UTF-8,因为它们都按预期工作:

$ cat file
ελα ρε
王小红
$ perl -pe '' file
ελα ρε
王小红

不幸的是,没有-CIO,perl也无法正确处理文件:

$ perl -pe 's/.*(..)$/$1/' file
ε
��

它也不应该是区域设置问题:

$ locale
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=

我猜我需要安装一些 Perl 软件包,但我不知道是哪些。一些相关信息:

$ perl --version | grep subversion
This is perl 5, version 22, subversion 0 (v5.22.0) built for x86_64-linux-thread-multi

$ pacman -Qs unicode
local/fribidi 0.19.7-1
    A Free Implementation of the Unicode Bidirectional Algorithm
local/icu 55.1-1
    International Components for Unicode library
local/libunistring 0.9.6-1
    Library for manipulating Unicode strings and C strings
local/perl 5.22.0-1 (base)
    A highly capable, feature-rich programming language
local/perl-unicode-stringprep 1.105-1
    Preparation of Internationalized Strings (RFC 3454)
local/perl-unicode-utf8simple 1.06-5
    Conversions to/from UTF8 from/to characterse
local/ttf-arphic-uming 0.2.20080216.1-5
    CJK Unicode font Ming style

我怎样才能让我的 Perl 安装与 Unicode 兼容?

答案1

您描述的问题是我测试的系统上的标准行为。IO影响标准输入和标准输出,所以这应该有效:

→ cat data | perl -CIO -pe 's/.*(..)$/$1/'
ρε
小红

然而这可能不会:

→ perl -CIO -pe 's/.*(..)$/$1/' data
ε
º¢

还有两个选项perl -C产生您想要的行为。

i     8   UTF-8 is the default PerlIO layer for input streams
o    16   UTF-8 is the default PerlIO layer for output streams

这基本上是对 perl 说,使用文件打开形式:

open(F, "<:utf8", "data");

或者你可以使用perl -CSDwhich 的简写perl -CIOEio

S     7   I + O + E
D    24   i + o

然后你得到

→ perl -CSD -pe 's/.*(..)$/$1/' data
ρε
小红

如果PERLIO设置了环境变量并包含:utf8此行为,也将启用。

看起来默认行为perl在配置/编译时也无法修改(下面的 cuonglm 评论)。拱门当然不会设置任何东西。我怀疑 debian perl 软件包会修改默认行为。

答案2

这不是系统的问题,而是它perl本身的问题。

-CIOSTDIN仅在和上设置 UTF-8 编码STDOUT,这是三个perl预定义文件句柄中的两个(您也有-Efor )。STDERR

当您使用:

perl -CIO -pe 's/.*(..)$/$1/' file

perl使用菱形运算<>符处理文件。从什么时候<>开始使用钻石算子open(有两个参数形式)要从命令行为每个文件创建新的文件句柄,这些文件句柄不会受到您在STDIN和上设置的 UTF-8 编码的影响STDOUT

因此,您可以通过其标准输入将文件的内容传递给它perl,它将起作用:

perl -CIO -pe 's/.*(..)$/$1/' <file

对于其他选项,请参阅@马特的回答


如果您想perl使用您的语言环境作为默认编码层,您可以使用:

perl -Mopen=:locale -pe 's/.*(..)$/$1/' file

当您用于PERLIO设置编码层时,您应该使用:encoding(uf8)而不是:utf8

使用:utf8跳过编码步骤,在读取无效的 UTF-8 字节序列时可能会导致问题并导致安全问题。

相关内容