utf8 && locale
Perl má podporu pre UNICODE a rôzne znakové sady ale napísať kód ktorý pracuje správne s UTF-8 ešte nieje veľmy primočiare a jednoduché. Stále prichádzajú znova a znova otázky ohľadne tejto témy. Jan poslal otázku na mailing list, nesôr som čítal podobnú otázku diskutovanú na CZ/SK Debian mailing liste. Tak sa na to pozrime na príklade:
#!/usr/bin/perl
my @pole=qw(šiška marek ucho čaj žička);
@pole=sort(@pole); # utriediť pole
foreach my $a (@pole) {
$a =~ s/\W//g; # vymazať všetky "neslovné" znaky
print "$a\n";
}
open my $handle, ">file.txt" or die "Can't write to file.txt: $!";
print $handle "\Uěščřžabcd\E\n"; # vypíš znaky ako veľké písmená
close $handle;
Nám vypíše:
marek ucho aj ika ika ěščřžABCD
Veľa chybyčiek krásy a výsledok zrovna nieje to čo sme čakali. čaj, šiška and žička sú na konci a neboli utriedené dobre, ěščřž zostalo ako bolo a písmená s diakritikou neboli považované za znaky slov.
Naučme Perl abecedu
Najskôr, Perl nepracuje správne so stringom keďže triedenie a pattern
matching nepoužilo všetky znaky ako malo. To je preto, lebo nie všetky
lazyky používajú tú istú abecedu. Kým niektoré jazyky môžu mať (a majú
samozrejme) tie isté znaky, triedenie môže byť iné. Perl nevie v ako jazyku
je string napísaný takže ich nevie správne utriediť. Aby sme mu to "ukázali"
musíme mu povedať aby používal špecifickú "locale" (abecedu), potom bude
vedieť ktoré znaky sú písmená a aké majú poradie. Toto sa udeje pomocout
use locale;, keď to pridáme výstup vyzerá následovne:
aj marek ika ucho ika ěščřžABCD
Parsovanie zdrojového kódu v rôznych jazykoch
V predchádzajúcom odstavci sme si ukázali ako naučiť Perl abecedu. Problémom je, že Perl stále nevie ako prečítať náš text. Vie prečítať string zo súborov a STDIN ale nie zo svojho zdrojového kódu. To je preto, že Perl počíta s tým že zdrojový kód je v default encoding ktoré NIEJE UTF-8 (asi ASCII alebo Latin-1, niesom si istý). Aby sme to opravili musíme mu povedať v akom kódovaní je zdrojový kód. Toto sa dá spraviť troma spôsobmi:
Pridaním use utf8;. Perl prečíta zdrojový kód ako UTF-8 súbor,
takže "prijme" všetky znaky s diakritikou a ostatné znaky definované v UTF-8
znakovej sade.
Pridaním use encoding 'utf8';. Táto pragma má výhodu tohom že
sa dá špecifikovať kódovanie aj iné ako utf8.
Používaním escape sequences pre všetky non ASCII znaky. Napríklad, na napísanie Á sa dá použiť "\x{C1}" čo korešponduje s UNICODE znakom pre LATIN CAPITAL LETTER A WITH ACUTE. Toto je celkom univerzálne, zdroják je celý v ASCII ale vcelku sa to zle číta a udržiava.
Keď je zdrojový súbor načítaný v správnom kódovaní tak máme dobrý výsledok aj na výstupe.
Wide character in print at ./utf8-test.pl line 15. čaj marek Wide character in print at ./utf8-test.pl line 15. šiška ucho Wide character in print at ./utf8-test.pl line 15. žička Wide character in print at ./utf8-test.pl line 18. ĚŠČŘŽABCD
I/O v UTF-8
Teraz je text vypísaný ako sme očakávali. Ale stále máme problém s výpisom UTF-8 znakov, STDOUT neočakáva UTF-8. To sa dá ošetriť rôznymi spôsobmi:
Prvé riešenie je pridať use encoding 'utf8';, to povie
Perl-u, že zdrojový kód je v UTF-8 a zároveň nastaví PerlIO layers pre
STDIN a STDOUT na UTF-8. V podstate sú use encoding 'utf8'; a
use utf8; skoro rovnaké okrem toho že ten prvý nastavý
kódovanie pre STDIN a STDOUT (STDERR zostáva nezmenený).
Druhá alternatíva je manuálne nastaviť kódovanie pre STDOUT pomocou
binmode(STDOUT => ':encoding(utf8)'). To sa dá uplatniť
na všetky file handle and nieje limitované pre STDOUT. Je to asi najlepšie
riešenie, lebo všetky ostatné PerlIO zostanú nezmenené aj keď sa použije
use encoding.
A nakoniec, kódovanie pre PerlIO layer sa dá nastaviť priamo pri otváraní
súboru pomocou open. Napríklad nasledujúci kód
open my $handle, "<:utf8", "file" or die "Can't read file: $!";
otvorí súbor v UTF-8.
Keď povieme Perl-u aby robil I/O v UTF-8 všetko je v poriadku:
čaj marek šiška ucho žička ĚŠČŘŽABCD
Nuž a pre úplnosť tu je finálny test script:
#!/usr/bin/perl
use warnings;
use strict;
# Utrieď string podľa aktuálneho kódovania a používanej abecedy
use locale;
# načítaj zdrojovy kód ak UTF-8 a nastav STDOUT a STDIN na UTF-8
use encoding 'utf8';
# môžeme písať UTF-8 znaky v kóde vďaka "use encoding"
my @pole=qw(šiška marek ucho čaj žička);
# sort rozpoznáva všetk znaky abecedy vďaka "use locale"
@pole=sort(@pole); # sort array
foreach my $a (@pole) {
# pattern matching funguje vďaka "use locale"
$a =~ s/\W//g; # vymazať všetky "neslovné" znaky
print "$a\n"; # vypíš prvok poľa
}
# zapíš UTF-8 do súboru
open my $handle, ">:utf8", "file.txt" or die "Can't write to file.txt: $!";
# vieme zneniť znaky na veľké písmená vďaka "use locale"
print $handle "\Uěščřžabcd\E\n"; # vypíš znaky ako veľe písmená
close $handle;
Poznánky
Keď chceme písať znaky iné ako Latin-1 do Pod dokumentácie treba nastaviť kódovanie nasledovne:
=encoding utf-8
Linky: utf8 - Perl pragma to enable/disable UTF-8 (or UTF-EBCDIC) in source code, locale - Perl pragma to use and avoid POSIX locales for built-in operations, perlunitut - Perl Unicode Tutorial, perluniintro - Perl Unicode introduction, perlunicode - Unicode support in Perl
29. Jun 2008
Jozef
03. Aug 2008
Emmanuel
en