A partire da Perl 5.6, il Perl ha avuto un certo livello di supporto ai
caratteri multibyte. Si raccomanda il Perl 5.8 o successivo. Le raccolte di
caratteri multibyte supportate includono Unicode e le codifiche precedenti
(per questioni di compatibilità attraverso il modulo Encode.
Consultate perluniintro, perlunicode, ed Encode.
Se siete è fermi alle vecchie versioni di Perl, potete fare
Unicode con il modulo Unicode::String e la conversione di caratteri
usando i moduli Unicode::Map8 e Unicode::Map. Se si stanno usando
codici giapponesi, potreste provare ad utilizzare jperl 5.005_03.
Infine, il seguente insieme di approcci viene fornito da Jeffrey Friedl,
il cui articolo sul numero #5 di The Perl Journal parla di questo stesso
argomento.
Supponiamo abbiate qualche strano codice Marziano nel quale le coppie di
lettere maiuscole ASCII codificano le singole lettere Marziane
(cioè i due byte "CV" formano una singola lettera Marziana,
come pure fanno i due byte "SG", "VS", "XX", ecc.). Gli altri byte
rappresentano singoli caratteri, proprio come in ASCII.
Dunque, la stringa in marziano "Io sono CVSGXX!" utilizza 15 byte
per codificare i dodici caratteri 'I', 'o', ' ', 's', 'o', 'n', 'o', ' ',
'CV', 'SG', 'XX', '!'.
Ora, diciamo che si vuole cercare il singolo carattere /GX/. Perl non
conosce il Marziano, dunque troverà i due byte "GX" nella stringa
"Io sono CVSGXX!", anche se quel carattere non è lì:
gli assomiglia solamente perché "SG" è vicino a "XX",
ma non c'è alcun vero "GX". Questo è un grosso problema.
Qui di seguito ci sono alcuni modi, tutti gravosi, per occuparsi di
ciò:
$marziano =~ s/([A-Z][A-Z])/ $1 /g; # Ci si assicura che i byte
# "marziani" adiacenti
# non siano ancora adiacenti
print "GX trovato!" if $marziano =~ /GX/;
Oppure così:
@caratteri = $marziano =~ m/([A-Z][A-Z]|[^A-Z])/g;
# quanto scritto sopra e` concettualmente
# simile a: @caratteri = $testo =~ m/(.)/g;
#
foreach $carattere (@caratteri) {
print "GX trovato!", last if $carattere eq 'GX';
}
Oppure così:
while ($marziano =~ m/\G([A-Z][A-Z]|.)/gs) {# \G E<egrave> probabilmente inutile
print "GX trovato!\n", last if $1 eq 'GX';
}
Ecco un altro modo, un po' meno ripido, per risolvere il problema,
opera di Bejamin Goldberg, che usa una zero-width negative look-behind assertion
[asserzione negativa di ampiezza zero con ricerca all'indietro, NdT]
print "GX trovato!\n" if $marziano =~ m/
(?<![A-Z])
(?:[A-Z][A-Z])*?
GX
/x;
Questa soluzione ha successo se il carattere "marziano" GX è
contenuto nella stringa, mentre fallisce in tutti gli altri casi. Se
non vi garba l'utilizzo di (?!>), una zero-width negative
look-behind assertion, potete sostituire (?!<[A-Z]) con
(?:^|[^A-Z]).
Questo sistema ha l'effetto collaterale di inserire la cosa sbagliata
din $-[0] e $+[0], ma di solito si può aggirare questo problema.
|