Warum funktioniert mein Perl nicht gut mit Unicode?

Warum funktioniert mein Perl nicht gut mit Unicode?

Auf meiner neuen Arch-Installation perlfunktioniert Unicode anscheinend nicht einwandfrei. Als Beispiel sei diese Eingabedatei angegeben:

ελα ρε
王小红

Dieser Befehl sollte mir die letzten beiden Zeichen jeder Zeile geben:

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

Wie Sie oben sehen können, erhalte ich jedoch Kauderwelsch. Die korrekte Ausgabe lautet:

ρε
小红

Ich weiß, dass mein Terminal ( gnome-terminator) UTF-8 unterstützt, da beide wie erwartet funktionieren:

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

Leider geht auch ohne nicht richtig mit den Dateien um -CIO:perl

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

Es sollte auch kein Gebietsschemaproblem sein:

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

Ich vermute, dass ich einige Perl-Pakete installieren muss, aber ich weiß nicht, welche. Einige relevante Informationen:

$ 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

Wie kann ich meine Perl-Installation so einrichten, dass sie gut mit Unicode funktioniert?

Antwort1

Bei dem von Ihnen beschriebenen Problem handelt es sich um ein Standardverhalten auf den Systemen, auf denen ich es getestet habe. IEs Obetrifft stdin und stdout, also sollte Folgendes funktionieren:

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

Dies könnte jedoch nicht der Fall sein:

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

Es gibtzwei weitere Optionen fürperl -Cdie das gewünschte Verhalten hervorrufen.

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

Damit wird Perl im Wesentlichen gesagt, dass es ein Formular zum Öffnen von Dateien verwenden soll:

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

oder Sie können verwenden, perl -CSDwas eine Abkürzung ist fürperl -CIOEio

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

Dann bekommst du

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

Wenn die PERLIOUmgebungsvariable festgelegt ist und enthält, :utf8wird dieses Verhalten ebenfalls aktiviert.

Es sieht so aus, als ob das Standardverhalten perlauch zur Konfigurations-/Kompilierungszeit nicht veränderbar ist (cuonglm-Kommentar unten). Arch kann das jedenfalls nichtetwas einstellen.Ich bezweifle, dass Debian-Perl-Pakete das Standardverhalten ändern würden.

Antwort2

Das ist kein Systemproblem, sondern ein Problem des Systems perlselbst.

-CIOStellen Sie nur die UTF-8-Kodierung auf STDINund ein STDOUT, zwei der drei perlvordefinierten Dateihandles (die Sie auch -Efür haben).STDERR

Bei Verwendung von:

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

perlVerwenden Sie den Diamant-Operator <>zur Dateiverarbeitung. Seit wann wird der Diamant-Operator <>verwendet ?offen (mit zwei Argumenten)STDINum über die Befehlszeile für jede Datei einen neuen Dateihandle zu erstellen. Diese Dateihandles werden von der von Ihnen auf und festgelegten UTF-8-Kodierung nicht beeinflusst STDOUT.

Sie können also den Inhalt der Datei perlüber deren Standardeingabe übergeben und es wird funktionieren:

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

Weitere Optionen finden Sie unter@Matts Antwort.


Falls Sie perlIhr Gebietsschema als Standardcodierungsebene verwenden möchten, können Sie Folgendes verwenden:

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

Wenn Sie PERLIOzum Einstellen der Kodierungsebene verwenden, sollten Sieverwenden :encoding(uf8)statt:utf8.

Durch die Verwendung :utf8wird der Kodierungsschritt übersprungen. Dies kann beim Lesen ungültiger UTF-8-Bytefolgen zu Problemen führen und Sicherheitsprobleme verursachen.

verwandte Informationen