Por que meu Perl não funciona bem com Unicode?

Por que meu Perl não funciona bem com Unicode?

Na minha nova instalação do Arch, perlnão parece funcionar bem com Unicode. Por exemplo, dado este arquivo de entrada:

ελα ρε
王小红

Este comando deve me fornecer os dois últimos caracteres de cada linha:

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

No entanto, como você pode ver acima, fico sem sentido. A saída correta é:

ρε
小红

Eu sei que meu terminal ( gnome-terminator) suporta UTF-8, pois ambos funcionam conforme o esperado:

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

Infelizmente, sem -CIO, perltambém não lida com os arquivos corretamente:

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

Também não deve ser um problema de localidade:

$ 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=

Acho que preciso instalar alguns pacotes Perl, mas não sei quais. Algumas informações relevantes:

$ 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

Como posso fazer com que minha instalação Perl funcione bem com Unicode?

Responder1

O problema que você está descrevendo é o comportamento padrão nos sistemas em que testei. Ie Oafeta stdin e stdout, então isso deve funcionar:

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

Considerando que isso pode não:

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

mais duas opções paraperl -Cque produzem o comportamento desejado.

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

O que basicamente quer dizer para Perl, use um formulário de abertura de arquivo:

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

ou você pode usar perl -CSDwhich é uma abreviação deperl -CIOEio

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

Então você consegue

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

Se a PERLIOvariável de ambiente estiver definida e incluir, :utf8esse comportamento também será habilitado.

Parece que o comportamento padrão perltambém não pode ser modificado no momento da configuração/compilação (comentário cuonglm abaixo). Arch certamente nãodefinir qualquer coisa.Duvido que os pacotes debian perl modifiquem o comportamento padrão.

Responder2

Isso não é um problema do sistema, mas em perlsi.

-CIOdefina apenas a codificação UTF-8 STDINe STDOUT, dois dos três perlidentificadores de arquivo predefinidos (você também tem -Epara ).STDERR

Quando você usa:

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

perluse o operador diamante <>para processar o arquivo. Desde quando o operador de diamante <>usouaberto (com forma de dois argumentos)para criar um novo identificador de arquivo para cada arquivo na linha de comando, esse identificador de arquivo não será afetado pela codificação UTF-8 definida em STDINe STDOUT.

Então, você pode passar o conteúdo do arquivo perlatravés de seu stdin, e ele funcionará:

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

Para outras opções consulteResposta de @Matt.


Caso queira perlusar sua localidade para camada de codificação padrão, você pode usar:

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

Ao usar PERLIOpara definir a camada de codificação, você deveusar :encoding(uf8)em vez de:utf8.

Usar :utf8ignora a etapa de codificação e pode causar problemas ao ler sequências de bytes UTF-8 inválidas e causar problemas de segurança.

informação relacionada