為什麼我的 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 位元組序列時可能會導致問題並導致安全性問題。

相關內容