NOME

perlunicode - Supporto Unicode in Perl

DESCRIZIONE

Avvertenze Importanti

Un supporto completo Unicode richiede una gran quantità di lavoro. Sebbene Perl non implementi lo standard Unicode e i rapporti tecnici allegati da parte a parte, Perl fornisce comunque una gran quantità di funzionalità Unicode.

Strati di Input e Output

Perl sa che un filehandle usa la codifica Unicode interna (UTF-8, o UTF-EBCDIC su piattaforme EBCDIC) se il filehandle viene aperto con lo strato :utf8. Altre codifiche possono essere convertite alla codifica interna Perl in lettura (o viceversa in scrittura) usando lo strato :encoding(...). Leggete open.

Per indicare che il sorgente stesso dello script è in una particolare codifica, usate encoding.

Espressioni Regolari

Il compilatore delle espressioni regolari produce istruzioni polimorfiche. Ovvero, l'espressione di adatta ai dati e commuta automaticamente allo schema di caratteri Unicode quando viene usata su dati Unicode -- o viceversa usa lo schema tradizionale a byte quando viene usata su dati a byte.

use utf8 è ancora necessario per usare UTF-8/UTF-EBCDIC negli script

Per compatibilità, la direttiva use utf8 deve essere inclusa esplicitamente per attivare il riconoscimento di stringhe in UTF-8 nei sorgenti degli script (nelle costanti stringa e espressioni regolari, o nei nomi degli identificatori) sulle macchine ASCII, ovvero il riconoscimento di UTF-EBCDIC sulle macchine EBCDIC. Questi sono i soli casi in cui è necessario un esplicito use utf8. Cfr. utf8.

Potete anche usare la direttiva encoding per cambiare la codifica di default per i dati nei vostri script; cfr. encoding.

Semantica a byte e a caratteri

A partire dalla versione 5.6, la rappresentazione interna delle stringhe in Perl è basata su caratteri "larghi" (nel senso che possono occupare più di un byte).

Nel futuro, si potrà supporre che le operazioni a livello di Perl lavoreranno su caratteri anziché byte.

Comunque, come misura di compatiblità temporanea, Perl cerca di fornire un percorso sicuro di migrazione per i vostri programmi da semantica a byte a semantica a caratteri. Nel caso di operazioni per le quali Perl può decidere senza ambiguità che i dati in ingresso sono caratteri, viene usata la semantica a caratteri. Nel caso di operazioni per le quali questa decisione non può essere effettuata senza ulteriori informazioni da parte dell'utente, Perl decide per la compatibilità e sceglie la semantica a byte.

Questo comportamento mantiene la compatiblità con versioni precedenti del Perl, che usavano la semantica a byte solo nel caso in cui nessuno degli input del programma erano indicati come sorgenti di caratteri Unicode. Questi dati possono provenire da filehandle, da chiamate a programmi esterni, da informazioni fornite dal sistema (ad esempio %ENV), o da costanti nel sorgente.

Sulle piattaforme Windows, se viene usata l'opzione a riga di comando -C, oppure se il flag globale ${^WIDE_SYSTEM_CALLS} è impostato a 1, tutte le chiamate di sistema useranno le corrispondenti API "wide-character" ("caratteri larghi", ovvero Unicode anziché ASCII, NdT). Questa funzionalità è disponibile solo su Windows per adattarsi agli standard già stabilit per quella piattaforma -- e ci sono ben poche piattaforme non-Windows che abbiano API che tengono conto di Unicode.

La direttiva bytes forzerà sempre, indipendentemente dalla piattaforma, la semantica a byte in un particolare scope lessicale. Cfr. bytes.

La direttiva utf8 è principalmente un sistema di compatibilità che attiva il riconoscimenti di costanti UTF-(8|EBCDIC) da parte del parser. Notate che questa direttiva è necessaria solo finché Perl assume una semantica a byte; quando la semantica a caratteri diventerà quella predefinita, questa direttiva potrà non avere più effetto. Cfr. utf8.

Tranne dove viene detto esplicitamente, gli operatori Perl usano la semantica a carattere per i dati Unicode e la semantica a byte per i dati non Unicode. La decisione di usare la semantica a carattere è fatta in modo trasparente. Se i dati provengono da una sorgente Unicode -- ad esempio, da un filehandle cui è stato applicato uno strato di codifica, o da una costante Unicode nel sorgente -- si applica la semantica a carattere. Altrimenti, si applica la semantica a byte. La direttiva bytes è usata per forzare la semantica a byte sui dati Unicode.

Se si concatenano stringe con semantica a byte e stringhe Unicode, la nuova stringa verrà aggiornata a ISO 8859-1 (Latin-1), anche se la stringa Unicode precedente usava EBCDIC. Questa trasformazione avviene senza considerare quale sia la codifica nativa a 8 bit del sistema; per cambiare questo in sistemi la cui codifica nativa non è né Latin-1 né EBCDIC usate la direttiva encoding. Cfr. encoding.

Secondo la semantica a carattere, molte operazioni che prima lavoravano sui byte ora lavorano sui caratteri. Un carattere in Perl è, a livello logico, un numero tra 0 e circa 2**31. I caratteri con valore più alto potrebbero essere codificati internamente con sequenze di byte più lunghe, ma questi dettagli sono quasi del tutto nascosti al codice Perl. Leggete perluniintro per ulteriori informazioni.

Effetti della semantica a carattere

La semantica a carattere ha gli effetti seguenti:

  • Le stringhe -- incluse le chiavi degli hash -- e le espressioni regolari possono contenere caratteri aventi valore ordinale maggiore di 255.

    Se usate un editor Unicode per scrivere i vostri programmi, i caratteri Unicode possono essere inseriti direttamente nelle costanti stringa in una qualunque delle vari codifiche di Unicode (UTF-8, UTF-EBCDIC, UTF-16, etc.), ma verranno riconosciuti come tali e convertiti nella codifica interna del Perl solo se la codifica è stata indicata con un'apposita direttiva encoding.

    Potete inserire caratteri Unicode all'interno di una stringa anche usando la notazione \x{...}. Tre le graffe dovete inserire il code point Unicode del carattere, in esadecimale. Ad esempio, una faccina sorridente è \x{263A}. Questo metodo funziona soltanto per i caratteri con valore maggiore o uguale a 0x100.

    Inoltre, se scrivete

    use charnames ':full';

    potete usare la notazione \N{...} inserendo tre le graffe il nome ufficiale Unicode del carattere, come ad esempio \N{WHITE SMILING FACE}.

  • Se avete specificato una codifica con un'opportuna direttiva encoding, gli identificatori nello script Perl possono contenere caratteri alfanumerici Unicode, ideogrammi inclusi. Al momento Perl non tenta di canonicalizzare i nomi di variabile.

  • Le espressioni regolari fanno match su caratteri anziché byte. "." fa match su un carattere anziché su un byte. Il pattern "\C" forza il match di un singolo byte -- si chiama \C perché un byte nel linguaggio C viene chiamato char.

  • Le classi di caratteri nelle espressioni regolari fanno match su caratteri anziché byte e fanno match sulle proprietà dei caratteri specificate nel database delle proprietà Unicode. Ad esmepio, "\w" può essere usato per far match su un ideogramma giapponese.

  • Proprietà Unicode, script, e blocchi possono essere usati per nome come classi di caratteri usando il pattern \p{} "fa match su proprietà" e la sua negazione \P{}.

    Ad esempio, \p{Lu} fa match con un qualsiasi carattere che abbia la proprietà Unicode "Lu" (lettera maiuscola, da "Letter, uppercase"), mentre \p{M} fa match su qualsiasi carattere con la proprietà "M" (accenti e simili, da "Mark"). Le graffe non sono necessarie per proprietà di una sola lettera, per cui \p{M} è uguale a \pM. Sono disponibili molte proprietà predefinite, come ad esempio \p{Mirrored} o \p{Tibetan}.

    I nomi ufficiali Unicode di script e blocchi usano spazi e trattini come separatori, ma per comodità potete usare trattini, spazi, o sottolineature, e non vengono distinte maiuscola da minuscole. Si suggerisce, comunque, che per consistenza usiate la seguente convenzione: usate il nome ufficiale Unicode per lo script, la proprietà, o il blocco (ma leggete sotto per le regole aggiuntive che si applicano ai nomi di blocco), tolti spazi e trattini, con ciascuna parola avente la sola prima lettera maiuscola. Così Latin-1 Supplement diventa Latin1Supplement.

    Potete anche usare la negazione, sia in \p{} che in \P{} inserendo un circonflesso (^) tra la graffa aperta e il nome della proprietà: \p{^Tamil} è equivalente a \P{Tamil}.

    Quelle che seguono sono le proprietà base della categoria "generale" di Unicode, assieme alla loro forma estesa (e a una traduzione, NdT). Potete usare l'una o l'altra; ad esempio, \p{Lu} e \p{LowercaseLetter} sono identici.

    Breve       Estesa                 Traduzione
    
    L           Letter                 lettera
    Lu          UppercaseLetter        lettera maiuscola
    Ll          LowercaseLetter        lettera minuscola
    Lt          TitlecaseLetter        lettera da titolo
    Lm          ModifierLetter         lettera modificatrice
    Lo          OtherLetter            altra lettera
    
    M           Mark                   diacritico
    Mn          NonspacingMark         diacritico senza larghezza
    Mc          SpacingMark            diacritico con larghezza
    Me          EnclosingMark          diacritico circoscritto
    
    N           Number                 cifra
    Nd          DecimalNumber          cifra decimale
    Nl          LetterNumber           cifra lettera
    No          OtherNumber            altra cifra
    
    P           Punctuation            punteggiatura
    Pc          ConnectorPunctuation   punteggiatura legante
    Pd          DashPunctuation        punteggiatura tratto
    Ps          OpenPunctuation        punteggiatura di apertura
    Pe          ClosePunctuation       punteggiatura di chiusura
    Pi          InitialPunctuation     punteggiatura iniziale
                (puo` comportarsi come Ps o Pe a seconda dell'uso)
    Pf          FinalPunctuation       punteggiatura finale
                (puo` comportarsi come Ps o Pe a seconda dell'uso)
    Po          OtherPunctuation       altra punteggiatura
    
    S           Symbol                 simbolo
    Sm          MathSymbol             simbolo matematico
    Sc          CurrencySymbol         simbolo di valuta
    Sk          ModifierSymbol         simbolo modificatore
    So          OtherSymbol            altro simbolo
    
    Z           Separator              separatore
    Zs          SpaceSeparator         separatore spazio
    Zl          LineSeparator          separatore linea
    Zp          ParagraphSeparator     separatore paragrafo
    
    C           Other                  altro
    Cc          Control                controllo
    Cf          Format                 formato
    Cs          Surrogate              surrogato
                (non usabile)
    Co          PrivateUse             uso privato
    Cn          Unassigned             non assegnato

    Proprietà di una sola lettera fanno match con caratteri che abbiano una qualsiasi delle proprietà di due lettere che cominciano con essa. L& è un caso speciale, è sinonimo di Ll, Lu e Lt.

    Poiché Perl evita all'utente di dover comprendere la rappresentazione interna dei caratteri Unicode, non c'è bisogno di implementare il concetto piuttosto scomodo dei surrogati. Perciò Cs non è supportata.

    Poiché gli script differiscono nella loro direzionalità -- l'ebraico è scritto da destra a sinistra, ad esempio -- Unicode fornisce le seguenti proprietà:

    Proprieta`  Significato
    
    BidiL       Sinistra-Destra
    BidiLRE     Sinistra-Destra Immerso
    BidiLRO     Sinistra-Destra Forzato
    BidiR       Destra-Sinistra
    BidiAL      Destra-Sinistra Arabo
    BidiRLE     Destra-Sinistra Immerso
    BidiRLO     Destra-Sinistra Forzato
    BidiPDF     Estrai formato direzionale
    BidiEN      Numero Europeo
    BidiES      Separatore di Numero Europeo
    BidiET      Terminatore di Numero Europeo
    BidiAN      Numero Arabo
    BidiCS      Separatore Comune di Numero
    BidiNSM     Diacritico senza larghezza
    BidiBN      Ininfluente al bordo
    BidiB       Separatore di Paragrafo
    BidiS       Separatore di Segmento
    BidiWS      Spazio
    BidiON      Altri ininfluenti

    Ad esempio, \p{BidiR} fa match sui caratteri che sono normalmente scritti da destra a sinistra.

Script

I nomi degli script che possono essere usati con \p{...} e \P{...}, come ad esempio \p{Latin} o \p{Cyrillic}, sono i seguenti:

Arabic
Armenian
Bengali
Bopomofo
Buhid
CanadianAboriginal
Cherokee
Cyrillic
Deseret
Devanagari
Ethiopic
Georgian
Gothic
Greek
Gujarati
Gurmukhi
Han
Hangul
Hanunoo
Hebrew
Hiragana
Inherited
Kannada
Katakana
Khmer
Lao
Latin
Malayalam
Mongolian
Myanmar
Ogham
OldItalic
Oriya
Runic
Sinhala
Syriac
Tagalog
Tagbanwa
Tamil
Telugu
Thaana
Thai
Tibetan
Yi

Classi di proprietà estese possono aggiungersi a quelle base, definite nel database Unicode PropList (con spiegazione in italiano, NdT):

ASCIIHexDigit                   cifra esadecimale ASCII
BidiControl                     controllo bidirezionalita`
Dash                            trattino
Deprecated                      deprecato
Diacritic                       diacritico (accenti etc.)
Extender                        estensore
GraphemeLink                    collegamento tra grafemi
HexDigit                        cifra esadecimale
Hyphen                          trattino di sillabazione
Ideographic                     ideografico
IDSBinaryOperator               operatore binario IDS
IDSTrinaryOperator              operatore ternario IDS
JoinControl                     controllo di legatura
LogicalOrderException           eccezione di ordine logico
NoncharacterCodePoint           code point non carattere
OtherAlphabetic                 altri alfabetici
OtherDefaultIgnorableCodePoint  altro code point normalmente
                                ignorabile
OtherGraphemeExtend             altra estensione di grafema
OtherLowercase                  altra minuscola
OtherMath                       altro carattere matematico
OtherUppercase                  altra maiuscola
QuotationMark                   virgoletta
Radical                         radicale
SoftDotted                      con puntino eliminabile
TerminalPunctuation             punteggiatura terminale
UnifiedIdeograph                ideogramma unificato
WhiteSpace                      spazio

e ci sono ancora proprietà derivate:

Alphabetic      Lu + Ll + Lt + Lm + Lo + OtherAlphabetic
Lowercase       Ll + OtherLowercase
Uppercase       Lu + OtherUppercase
Math            Sm + OtherMath

ID_Start        Lu + Ll + Lt + Lm + Lo + Nl
ID_Continue     ID_Start + Mn + Mc + Nd + Pc

Any             Ogni carattere
Assigned        Ogni carattere non in Cn (sinonimo di \P{Cn})
Unassigned      Sinonimo di \p{Cn}
Common          Ogni carattere (o code point non assegnato)
                non esplicitamente assegnato a uno script

Per compatibilità con Perl 5.6, tutte le proprietà menzionate finora possono essere indicate anche preponendo Is al loro nome, per cui as esempio \P{IsLu} è uguale a \P{Lu}.

Blocchi

Oltre agli script, Unicode definisce anche dei blocchi di caratteri. La differenza tra script e blocchi è che il concetto di script è più vicino ai linguaggi naturali, mentre il concetto di blocco è più un raggruppamento artificioso basato su gruppi di 256 caratteri. Ad esempio, lo script Latin contiene lettere da svariati blocchi, ma non contiene ciascun carattere da tutti quei blocchi. Ad esempio, non contiene le cifre, essendo queste condivise tra molti script. Cifre e altri caratteri condivisi, come ad esempio la punteggiatura, appartengono alla categoria chiamata Common.

Per maggiori informazioni sugli script, leggete UTR #24:

http://www.unicode.org/unicode/reports/tr24/

Per maggiori informazioni sui blocchi, leggete:

http://www.unicode.org/Public/UNIDATA/Blocks.txt

I nomi dei blocchi si indicano con il prefisso In. Ad esempio, per far match sui caratteri del blocco Katakana si usa \p{InKatakana}. Il prefisso In può essere omesso se non ci sono conflitti con il nome di uno script o di un'altra proprietà, ma si raccomanda di usare sempre In per indicare i blocchi, per evitare confusione.

Sono supportati i seguenti nomi di blocco:

InAlphabeticPresentationForms
InArabic
InArabicPresentationFormsA
InArabicPresentationFormsB
InArmenian
InArrows
InBasicLatin
InBengali
InBlockElements
InBopomofo
InBopomofoExtended
InBoxDrawing
InBraillePatterns
InBuhid
InByzantineMusicalSymbols
InCJKCompatibility
InCJKCompatibilityForms
InCJKCompatibilityIdeographs
InCJKCompatibilityIdeographsSupplement
InCJKRadicalsSupplement
InCJKSymbolsAndPunctuation
InCJKUnifiedIdeographs
InCJKUnifiedIdeographsExtensionA
InCJKUnifiedIdeographsExtensionB
InCherokee
InCombiningDiacriticalMarks
InCombiningDiacriticalMarksforSymbols
InCombiningHalfMarks
InControlPictures
InCurrencySymbols
InCyrillic
InCyrillicSupplementary
InDeseret
InDevanagari
InDingbats
InEnclosedAlphanumerics
InEnclosedCJKLettersAndMonths
InEthiopic
InGeneralPunctuation
InGeometricShapes
InGeorgian
InGothic
InGreekExtended
InGreekAndCoptic
InGujarati
InGurmukhi
InHalfwidthAndFullwidthForms
InHangulCompatibilityJamo
InHangulJamo
InHangulSyllables
InHanunoo
InHebrew
InHighPrivateUseSurrogates
InHighSurrogates
InHiragana
InIPAExtensions
InIdeographicDescriptionCharacters
InKanbun
InKangxiRadicals
InKannada
InKatakana
InKatakanaPhoneticExtensions
InKhmer
InLao
InLatin1Supplement
InLatinExtendedA
InLatinExtendedAdditional
InLatinExtendedB
InLetterlikeSymbols
InLowSurrogates
InMalayalam
InMathematicalAlphanumericSymbols
InMathematicalOperators
InMiscellaneousMathematicalSymbolsA
InMiscellaneousMathematicalSymbolsB
InMiscellaneousSymbols
InMiscellaneousTechnical
InMongolian
InMusicalSymbols
InMyanmar
InNumberForms
InOgham
InOldItalic
InOpticalCharacterRecognition
InOriya
InPrivateUseArea
InRunic
InSinhala
InSmallFormVariants
InSpacingModifierLetters
InSpecials
InSuperscriptsAndSubscripts
InSupplementalArrowsA
InSupplementalArrowsB
InSupplementalMathematicalOperators
InSupplementaryPrivateUseAreaA
InSupplementaryPrivateUseAreaB
InSyriac
InTagalog
InTagbanwa
InTags
InTamil
InTelugu
InThaana
InThai
InTibetan
InUnifiedCanadianAboriginalSyllabics
InVariationSelectors
InYiRadicals
InYiSyllables
  • Il pattern speciale \X fa match su una qualsiasi sequenza estesa Unicode -- una sequenza di caratteri combinati, "combining character sequence" nello standard -- in cui il primo carattere è un carattere base e i seguenti sono modificatori che si applicano al primo. \X equivale a (?:\PM\pM*).

  • L'operatore tr/// trasforma caratteri invece che byte. Notare che la funzionalità di tr///CU è stata rimossa. Per fare qualcosa di simile usate pack('U0', ...) e pack('C0', ...).

  • Gli operatori di cambio tra maiuscole e minuscole usano le tabelle di trasformazione Unicode quando vengono applicati a caratteri. Notate che uc(), o \U nelle stringhe interpolate, trasforma in maiuscolo, mentre ucfirst(), o \u nelle stringhe interpolate, trasforma in "maiuscole da titolo", nelle lingue che hanno questa distinzione.

  • La maggior parte degli operatori che trattano posizioni o lunghezze su stringhe passeranno automaticamente a usare posizioni di caratteri; tali operatori includono chop(), substr(), pos(), index(), rindex(), sprintf(), write(), e length(). Tra gli operatori che esplicitamente non cambiano ci sono vec(), pack(), e unpack(). Tra gli operatori per cui non fa differenza ci sono chomp(), gli opertatori che trattano le stringhe come mucchi di bit come sort(), e gli operatori che gestiscono i nomi di file.

  • Le lettere di formato c e C di pack() e unpack() non cambiano, poiché vengono spesso usate per formati orientati ai byte. Pensate al char del linguaggio C.

    Il nuovo specificatore U converte tra caratteri Unicode e code point.

  • Le funzioni chr() e ord() lavorano sui caratteri, in maniera simile a pack("U") e unpack("U"), e non come pack("C") e unpack("C"). pack("C") e unpack("C") sono metodi per emulare le funzioni chr() e ord() orientate ai byte su stringhe Unicode. Sebbene questi metodi mostrino la codifica interna delle stringhe Unicode, non si tratta di una cosa di cui dovreste normalmente preoccuparvi.

  • Gli operatori per stringhe di bit, & | ^ ~, possono lavorare su dati a carattere. Però, per compatibilità all'indietro con i casi in cui si usano questi operatori su stringhe i cui caratteri hanno tutti valore inferiore a 256, non dovreste usare ~ (il complemento a bit) quando i caratteri hanno valori sia sotto sia sopra 256. Più importante, le leggi di De Morgan (~($x|$y) eq ~$x&~$y e ~($x&$y) eq ~$x|~$y) non varranno. La ragione per questo fax pas matematico è che il complemento non può restituire sia il complemento a 8 bit (byte) che il complemento a larghezza di carattere.

  • lc(), uc(), lcfirst(), e ucfirst() funzionano nei seguenti casi:

    • la trasformazione va da un singolo carattere Unicode a un altro singolo carattere Unicode, oppure

    • la trasformazione va da un singolo carattere Unicode a più di un carattere Unicode.

    I casi seguenti non funzionano ancora:

    • la "sigma finale" (in Greco), e

    • ogni cosa che ha a che fare coi locale (Lituano, Turco, Azeri).

    Leggete il rapporto tecnico Unicode #21, "Case Mappings" ("Trasformazioni tra maiuscole e minuscole", NdT), per ulteriori dettagli.

  • E, infine, scalar reverse() rovescia per caratteri anziché per byte.

Proprietà dei caratteri definite dall'utente

Potete definire le vostre proprietà di carattere definendo delle subroutine con nomi che cominciano con In o Is. Queste subroutine devono essere visibile nel package che usa le proprietà. Le proprietà definite dall'utente possono essere usate nei costrutti \p e \P nelle espressioni regolari.

Le subroutine devono restituire una stringa in formato speciale, contenente una o più linee separate da a-capo. Ciascuna linea deve avere uno dei formati seguenti:

  • Due numeri esadecimali separati da spazi orizzontali (caratteri di spazio o tabulazione), indicante un intervallo di code point Unicode da includere.

  • Qualcosa da includere, preceduto da +: una delle proprietà predefinite (preceduta da utf8::), per indicare tutti i caratteri in quella proprietà; due numeri esadecimali per un intervallo di code point; o un singolo code point in esadecimale.

  • Qualcosa da escludere, preceduto da -: una delle proprietà predefinite (preceduta da utf8::), per indicare tutti i caratteri in quella proprietà; due numeri esadecimali per un intervallo di code point; o un singolo code point in esadecimale.

  • Qualcosa da negare, preceduto da !: una delle proprietà predefinite (preceduta da utf8::), per indicare tutti i caratteri tranne quelli in quella proprietà; due numeri esadecimali per un intervallo di code point; o un singolo code point in esadecimale.

Ad esempio, per definire una proprietà che copra entrambi i sistemi sillabici giapponesi (hiragana e katakana) potete definire

    sub InKana {
	return <<END;
    3040\t309F
    30A0\t30FF
    END
    }

(immaginando che il terminatore del documento immediato sia all'inizio della riga). Ora potete usare \p{InKana} e \P{InKana}.

Avremmo anche potuto usare i nomi di blocchi esistenti:

    sub InKana {
	return <<'END';
    +utf8::InHiragana
    +utf8::InKatakana
    END
    }

Supponiamo che vogliate indicare solo i caratteri allocati, e non i semplici intervalli dei blocchi: in altre parole, volete rimuovere i non-caratteri:

    sub InKana {
	return <<'END';
    +utf8::InHiragana
    +utf8::InKatakana
    -utf8::IsCn
    END
    }

La negazione è utile per definire (sorpresa!) negazioni di classi:

    sub InNotKana {
	return <<'END';
    !utf8::InHiragana
    -utf8::InKatakana
    +utf8::IsCn
    END
    }

Codifica dei caratteri per l'input e l'output

Leggete Encode.

Livello di supporto Unicode nelle espressioni regolari

La seguente lista describe tutte le funzionalità Unicode per espressioni regolari supportate al momento. I riferimenti a "Livello N" e i numeri di sezione si riferiscono al rapporto tecnico Unicode #19, "Linee guida per le espressioni regolari Unicode" ("Unicode Regular Expression Guidelines").

  • Livello 1 - Supporto Unicode di base

    2.1 Notazione esadecimale               - fatto         [1]
        Notazione per nome                  - fatto         [2]
    2.2 Categorie                           - fatto         [3][4]
    2.3 Sottrazione                         - MANCA         [5][6]
    2.4 Limiti semplice di parola           - fatto         [7]
    2.5 Match laschi semplici               - fatto         [8]
    2.6 Fine linea                          - MANCA         [9][10]
    
    [ 1] \x{...}
    [ 2] \N{...}
    [ 3] . \p{...} \P{...}
    [ 4] ora anche gli script (cfr. UTR#24 "Script Names") in
         aggiunta ai blocchi
    [ 5] c'e` la negazione
    [ 6] potete usare il look-ahead [a] o definire apposite
         proprieta` [b] per emulare la sottrazione
    [ 7] includiamo la categoria C<Lettern> tra i caratteri
         di parola
    [ 8] notare che Perl esegue il "Full case-folding" per i
         match, non il "Simple": as esempio, U+1F88 e` equivalente
         a U+1F00 U+03B9, non a U+1F80. Questo fa differenza per
         alcune lettere greche con alcuni modificatori: il "Full
         case-folding" decompone il carattere, mentre il "Simple"
         lo mapperebbe su un carattere singolo.
    [ 9] cfr. UTR#13 "Linee guida Unicode per i terminatori di
         linea" ("Unicode Newline Guidelines")
    [10] ^ e $ dovrebbero fare match anche su \x{85}, \x{2028}
         e \x{2029}
         (dovrebbe influenzare anche <>, $., e i numeri di riga)
         (\s fa match su \x{85}, \x{2028} and \x{2029})

    [a] Potete simulare la sottrazione tra classi usando il look-ahead. Ad esmepio, quello che secondo il TR18 potrebbe essere scritto come

    [{Greek}-[{UNASSIGNED}]]

    in Perl può essere scritto come:

    (?!\p{Unassigned})\p{InGreekAndCoptic}
    (?=\p{Assigned})\p{InGreekAndCoptic}

    Ma in questo particolare caso, probabilmente quello che volete è

    \p{GreekAndCoptic}

    che farà match sui caratteri assegnati facenti parti dello script greco.

    [b] Cfr. "Proprietà dei caratteri definite dall'utente"

  • Livello 2 - Supporto Unicode esteso

    3.1 Surrogati                           - MANCA  
    3.2 Equivalenti canonici                - MANCA         [11][12]
    3.3 Grafemi indipendenti da locale      - MANCA         [13]
    3.4 Parole indipendenti da locale       - MANCA         [14]
    3.5 Match laschi indipendenti da locale - MANCA         [15]
    
    [11] cfr. UTR#15 "Normalizzazione Unicode" ("Unicode Normalization")
    [12] c'e` Unicode::Normalize ma non e` integrato con le
         espressioni regolari
    [13] c'e` \X ma a questo livello . dovrebbe essere equivalente
    [14] servono tre classi, non solo \w e \W
    [15] cfr. UTR#21 "Trasformazioni tra maiuscole e minuscole"
         ("Case Mappings")
  • Livello 3 - Supporto dipendente da locale

    4.1 Categorie dipendenti da locale      - MANCA  
    4.2 Grafemi dipendenti da locale        - MANCA         [16][17]
    4.3 Parole dipendenti da locale         - MANCA  
    4.4 Match laschi dipendenti da locale   - MANCA  
    4.5 Intervalli dipendenti da locale     - MANCA  
    
    [16] cfr. UTR#10 "Algoritmi di collazione Unicode"
         ("Unicode Collation Algorithms")
    [17] c'e` Unicode::Collate ma non e` integrato con le
         espressioni regolari

Codifiche Unicode

I caratteri Unicode sono associati a code point, che sono numeri astratti. Per usare questi numeri, sono necessarie varie codifiche.

  • UTF-8

    UTF-8 è una codifica a lunghezza variabile (da 1 a 6 byte, per tutti i caratteri attualmente allocati ne sono sufficienti 4), indipendente dall'ordinamento dei byte. La codifica UTF-8 è trasparente se ci si limita ad ASCII (e qui si intende davvero ASCII, 7 bit, non una qualche altra codifica a 8 bit).

    La tabella seguente è presa da Unicode 3.2:

        Code Point         1o byte  2o byte  3o byte  4o byte
    
      U+0000..U+007F       00..7F
      U+0080..U+07FF       C2..DF   80..BF
      U+0800..U+0FFF       E0       A0..BF   80..BF
      U+1000..U+CFFF       E1..EC   80..BF   80..BF
      U+D000..U+D7FF       ED       80..9F   80..BF
      U+D800..U+DFFF       ******* mal formato *******
      U+E000..U+FFFF       EE..EF   80..BF   80..BF
     U+10000..U+3FFFF      F0       90..BF   80..BF   80..BF
     U+40000..U+FFFFF      F1..F3   80..BF   80..BF   80..BF
    U+100000..U+10FFFF     F4       80..8F   80..BF   80..BF

    Notate il A0..BF per U+0800..U+0FFF, il 80..9F per U+D000...U+D7FF, il 90..BF per U+10000..U+3FFFF, e il 80...8F per U+100000..U+10FFFF. Questi "buchi" sono causati dal fatto che UTF-8 corretto evita le codifiche non minime: tecnicamente è possibile codificare in UTF-8 un singolo code point in più di un modo, ma ciò è espressamente proibito, e bisogna sempre usare la codifica più breve possibile. Per cui questo è quello che fa Perl.

    Un altro modo di vedere la codifica è a livello di bit:

           Code Point              1o byte   2o byte   3o byte   4o byte
    
                      0aaaaaaa     0aaaaaaa
              00000bbbbbaaaaaa     110bbbbb  10aaaaaa
              ccccbbbbbbaaaaaa     1110cccc  10bbbbbb  10aaaaaa
    00000dddccccccbbbbbbaaaaaa     11110ddd  10cccccc  10bbbbbb  10aaaaaa

    Come potete vedere, i byte seguenti cominciano tutti con 10, e i bit iniziali del primo byte indicano quanti byte fanno parte della codifica del carattere.

  • UTF-EBCDIC

    Come UTF-8 ma "EBCDIC-safe", allo stesso modo che UTF-8 è ASCII-safe.

  • UTF-16, UTF-16BE, UTF16-LE, surrogati, e i BOM (Byte Order Mark)

    Quello che segue è soprattutto per riferimento e conoscenza generale di Unicode; Perl non usa questi costrutti internamente.

    UTF-16 è una codifica a 2 o 4 byte. I code point U+0000..U+FFFF sono codificati in una singola unità da 16 bit, e i code point U+10000..U+10FFFF sono codificati in due unità da 16 bit. Quest'ultimo caso usa i surrogati, con la prima unità chiamata surrogato alto ("high surrogate" NdT) e la seconda chiamata surrogato basso ("low surrogate" NdT).

    I surrogati sono code point lasciati da parte per codificare l'intervallo di code point U+10000..U+10FFFF in coppie di unità da 16 bit. I surrogati alti sono nell'intervallo U+D800..U+DBFF, e i surrogati bassi sono nell'intervallo U+DC00..U+DFFF. La codifica con i surrogati è

    $alto  = ($uni - 0x10000) / 0x400 + 0xD800;
    $basso = ($uni - 0x10000) % 0x400 + 0xDC00;

    e la decodifica è

    $uni = 0x10000 + ($alto - 0xD800) * 0x400 + ($basso - 0xDC00);

    Se provate a generare surrogati (ad esempio usando chr()), otterrete un avvertimento se gli avvertimenti sono abilitati, poiché tali code point non sono validi per caratteri Unicode.

    Avendo unità lunghe 16 bit, UTF-16 dipende dall'ordinamento dei byte. UTF-16 semplice può essere usato in memoria, ma se deve essere trasmesso o salvato su file bisogna scegliere tra UTF-16BE (big-endian) e UTF-16LE (little-endian).

    Questo introduce un altro problema: cosa succede se sapete solo che i dati sono in UTF-16, ma non sapete in che ordine? I Byte Order Mark, o BOM, sono una soluzione. Un carattere speciale è stato scelto in Unicode per essere usato come Byte Order Mark: il carattere con code point U+FEFF è il BOM.

    Il trucco è che se leggete un BOM, saprete l'ordinamento dei byte, visto che se è stato scritto su una piattaforma big-endian, leggerete i due byte 0xFE 0xFF, ma se è stato scritto su una piattaforma little-endian leggerete i due byte 0xFF 0xFE. (E se la piattaforma di partenza scriveva in UTF-8, leggerete i tre byte 0xEF 0xBB 0xBF).

    Questo trucco funziona perché il code point U+FFFE è garantito non essere un carattere valido, per cui la sequenza di byte 0xFF 0xFE è senza ambiguità "BOM rappresentato in forma little-endian" e non può essere "U+FFFE rappresentato in forma big-endian".

  • UTF-32, UTF-32BE, UTF32-LE

    La famiglia UTF-32 è molto simile a quella UTF-16, tranne per il fatto che le unità sono di 32 bit, e di conseguenza non serve il metodo dei surrogati. Le segnature BOM saranno 0x00 0x00 0xFE 0xFF per BE e 0xFF 0xFE 0x00 0x00 per LE.

  • UCS-2, UCS-4

    Codifiche definite dallo standard ISO 10646. UCS-2 è una codifica a 16 bit. A differenza di UTF-16, UCS-2 non può essere esteso oltre U+FFFF, poiché non usa i surrogati. UCS-4 è una codifica a 32 bit, funzionalmente identica a UTF-32.

  • UTF-7

    Una codifica a 7 bit (l'ottavo bit è sempre a 0), utile quando il sistema di trasferimento o immagazzinamento non gestisce bene dati a 8 bit. È definito dalla RFC 2152.

Implicazioni di sicurezza di Unicode

  • UTF-8 malformato

    Sfortunatamente, la specifica di UTF-8 lascia un po' di spazio all'interpretazione su quanti byte di output codificato si debbano generare per un dato carattere Unicode di input. Strettamente parlando, dovrebbe essere generata la sequenza più breve possibile, poiché altrimenti c'è la possibilità di overflow del buffer di input dal lato di lettura di una connessione UTF-8. Perl genera sempre la sequenza più breve, e con gli avvertimenti attivati Perl vi avvertirà nel caso di UTF-8 a lunghezza non minima assieme ad altre malformazioni, come l'uso di surrogati, che non sono davvero code point Unicode.

  • Le espressioni regolari si comportano in maniera leggermente differente se applicate a stringhe di byte o a stringhe di caratteri (Unicode). Ad esempio, la classe "caratteri di parola" \w funzionerà in modo diverso nei due casi.

    Nel primo caso, l'insieme di caratteri di \w è piuttosto ristretto: l'insieme di default di caratteri alfabetici, cifre, e il "_" -- oppure, se state usando un "locale" (cfr. perllocale), \w potrebbe contenere alcune altre lettere a seconda della vostra lingua e nazione.

    Nel secondo caso, l'insieme di caratteri di \w è molto, molto più esteso. La cosa più importante è che, anche limitatamente ai primi 256 caratteri, probabilmente includerà caratteri diversi: a differenza della maggior parte dei "locale", che sono specifici di una lingua e una nazione, Unicode classifica come \w tutti i caratteri che sono lettere da qualche parte. Ad esempio, il vostro "locale" potrebbe non pensare che LATIN SMALL LETTER ETH sia una lettera (tranne nel caso in cui parliate Islandese), ma Unicode la tratta come tale.

    Come discusso altrove, Perl tiene un piede (due zoccoli?) in ciascuno dei due mondi: il vecchio mondo dei byte, e il nuovo mondo dei caratteri, convertendo i byte in caratteri quando necessario. Se il vostro codice esistente non usa esplicitamente Unicode, non dovrebbe avvenire alcuna conversione automatica a caratteri. I caratteri non dovrebbero neppure venire riconvertiti in byte. È comunque possibile mescolare byte e caratteri (cfr. perluniintro), nel qual caso \w nelle espressioni regolari potrebbe cominciare a comportarsi differentemente. Controllate il vostro codice. Usate gli avvertimenti ("warning") e la direttiva string.

Unicode in Perl su piattaforme EBCDIC

La gestione di Unicode su piattaforme EBCDIC è ancora sperimentale. Su tali piattaforme, i rifermenti alla codifica UTF-8 in questo e altri documenti dovrebbero essere intesi come a indicare UTF-EBCDIC, specificato dal rapporto tecnico Unicode 16, tranne nel caso in cui si stiano proprio discutendo le differenze tra ASCII e EBCDIC. Non esiste né una direttiva utfebcdic né uno strato :utfebcdic; al loro posto, utf8 e :utf8 vengono usati per indicare la codifica a 8 bit "nativa" della piattaforma per Unicode. Leggete perlebcdic per una discussione più approfondita della questione.

"Locale"

Normalmente le impostazione di "locale" e Unicode non si influenzano a vicenda, ma ci sono un paio di eccezioni:

  • Se le vostre variabili di ambiente relative al "locale" (LANGUAGE, LC_ALL, LC_CTYPE, LANG) contengono la stringa 'UTF-8' o 'UTF8' (maiuscole o minuscole), la codifica predefinita di STDIN, STDOUT, STDERR, e di ogni file aperto successivamente è considerata essere UTF-8.

  • Perl cerca con tutte le sue forze di lavorare sia con Unicode sia col vecchio mondo a byte. Molto spesso questo è comodo, ma certe volte tenere così "il piede in due staffe" può causare problemi.

Uso di Unicode con XS

Se volete maneggiare dati Perl in Unicode nelle vostre estensioni XS, potreste trovare utili le seguenti funzioni. Leggete perlapi per i dettagli.

  • DO_UTF8(sv) restituisce true se il flag UTF8 è attivo e la direttiva bytes non è in uso. SvUTF8(sv) restituisce true se il flag UTF8 è attivo, senza tener conto della direttiva bytes. Il fatto che il flag UTF8 sia attivo non indica che lo scalare contenga caratteri con code point maggiori di 255 (o 127), e neppure che ci siano prorio caratteri. Il significato del flag UTF8 è che la sequenza di ottetti nella rappresentazione dello scalare è la sequenza codificata in UTF-8 dei code point dei caratteri di una stringa. Il fatto che il flag UTF8 sia a zero significa che ciascun ottetto in questa rappresentazione codifica un solo carattere con code point tra 0 e 255 nella stringa. In modello Unicode del Perl consiste nel non usare UTF-8 finché non è assolutamente necessario.

  • uvuni_to_utf8(buf, chr) scrive il code point di un carattere Unicode in un buffer, codificandolo in UTF-8, e restituisce un puntatore che punta dopo i byte UTF-8.

  • utf8_to_uvuni(buf, lenp) legge dei byte codificati in UTF-8 da un buffer e restituisce i code point dei caratteri Unicode e, opzionalmente, la lunghezza della sequenza di byte UTF-8.

  • utf8_length(start, end) restituisce la lunghezza del buffer in numero di caratteri codificati in UTF-8. sv_len_utf8(sv) restituisce la lunghezza di scalari codificati in UTF-8.

  • sv_utf8_upgrade(sv) converte la stringa dello scalare nella sua forma codificata in UTF-8. sv_utf8_downgrade(sv) fa l'opposto, se possibile. sv_utf8_encode(sv) è simile a sv_utf8_upgrade tranne che non imposta il flag UTF8. sv_utf8_decode() fa l'opposto di sv_utf8_encode(). Notate che nessuna di queste funzioni deve essere usata come interfaccia generica di codifica/decodifica: usate Encode in questi casi. sv_utf8_upgrade() è influenzata dalla direttiva encoding, ma sv_utf8_downgrade() no (poiché la direttiva encoding è progettata per essere una strada a senso unico).

  • is_utf8_char(s) restituisce true se il puntatore punta a una codifica valida in UTF-8 di un carattere.

  • is_utf8_string(buf, len) restituisce true se len byte del buffer sono UTF-8 valido.

  • UTF8SKIP(buf) restituisce il numero di byte usati dal carattere codificato nel buffer. UNISKIP(chr) restituisce il numero di byte necessari per codificare in UTF-8 il code point del carattere Unicode. UTF8SKIP() è utile ad esempio per iterare sui caratteri di un buffer codificato in UTF-8; UNISKIP() è utile, ad esempio, per calcolare la dimensione necessaria per un buffer codificato in UTF-8.

  • utf8_distance(a, b) restituisce la distanza in caratteri tra i due puntatori che puntano allo stesso buffer codificato in UTF-8.

  • utf8_hop(s, off) restituisce un puntatore a un buffer UTF-8 che dista off (positivo o negativo) caratteri dal buffer UTF-8 s. Attenzione a non sforare: utf8_hop() uscirà tranquillamente dall'inizio o dalla fine del buffer se gli viene richiesto.

  • pv_uni_display(dsv, spv, len, pvlim, flags) e sv_uni_display(dsv, ssv, pvlim, flags) sono utili per la visualizzazione in fase di debugging di stringhe e scalari Unicode. Normalmente sono utili sono in fase di debugging -- mostrano tutti i caratteri come code point in esadecimale -- ma usando i flag UNI_DISPLAY_ISPRINT, UNI_DISPLAY_BACKSLASH, e UNI_DISPLAY_QQ potete renderne l'output più leggibile.

  • ibcmp_utf8(s1, pe1, u1, l1, u1, s2, pe2, l2, u2) può essere usata per confrontare due stringhe Unicode considerando uguali maiuscole e minuscole. Per i confronti esatti usate semplicemente memEQ() e memNE() come al solito.

Per ulteriori informazioni, leggete perlapi, e utf8.c e utf8.h nella distribuzione del codice sorgente di Perl.

BUGS

Interazione con i "locale"

L'uso dei "locale" con dati Unicode può portare a strani risultati. Al momento, Perl cerca di associare le informazioni di "locale" a 8 bit ai caratteri tra 0 e 255, ma questa tecnica è dimostrabilmente sbagliata per i "locale" che usano caratteri fuori da quell'intervallo quando vengono mappati su Unicode. Inoltre, il supporto Unicode di Perl funzionerà un po' più lentamente. L'uso dei "locale" con Unicode è scoraggiato.

Interazione con le estensioni

Quando Perl scambia dati con un estensione, l'estensione dovrebbe essere in grado di capire il flag UTF8 e agire di conseguenza. Se l'estensione non sa come usare il flag, è probabile che restituisca dati con il flag impostato in maniera scorretta.

Perciò se state lavorando con dati Unicode, consultate la documentazione di ciascun modulo che state usando se ci sono problemi con lo scambio di dati Unicode. Se la documentazione non parla di Unicode, sospettate il peggio, e magari guardate il sorgente per capire come è implementato il modulo. I moduli scritti interamente in Perl non dovrebbero causare problemi. Moduli che accedono, direttamente o indirettamente, codice scritto in altri linguaggi, sono a rischio.

Per le funzioni affette, la strategia semplice per evitare corruzione dei dati consiste nel rendere sempre esplicita la codifica dei dati scambiati. Scegliete una codifica che sapete che l'estensione sa gestire. Convertite gli argomenti da passare all'estensione in quella codifica, e riconvertite alla rovescia i risultati. Scrivete funzioni di interfaccia che facciano le conversioni al posto vostro, così che possiate sostituirle quando l'estensione verrà aggiornata.

Per fare un esempio, diciamo che la funzione Foo::Bar::escape_html non gestisce ancora dati Unicode. La funzione di interfaccia converte gli argomenti in UTF-8 semplice e converte il risultato di nuovo nella rappresentazione interna Perl:

sub mio_escape_html ($) {
  my($cosa) = shift;
  return unless defined $cosa;
  Encode::decode_utf8(Foo::Bar::escape_html(Encode::encode_utf8($cosa)));
}

Certe volte, quando l'estensione non converte i dati ma si limita a immagazzinarli e recuperarli, vi troverete nella posizione di usare l'altrimenti pericolosa funzione Encode::_utf8_on(). Diciamo che la popolare estensione Foo::Bar, scritta in C, fornisce un metodo param che permette di immagazzinare e recuperare dati secondo queste segnature:

$self->param($name, $value);            # salva uno scalare
$value = $self->param($name);           # recupera uno scalar

Se l'estensione non fornisce ancora supporto per qualche codifica, potreste scrivere una classe derivata con un metodo param come questo:

sub param {
  my($self,$nome,$valore) = @_;
  utf8::upgrade($nome);     # ora e` sicuramente UTF-8
  if (defined $valore)
    utf8::upgrade($valore); # ora e` sicuramente UTF-8
    return $self->SUPER::param($nome,$valore);
  } else {
    my $ret = $self->SUPER::param($nome);
    Encode::_utf8_on($ret); # sappiamo che e` UTF-8
    return $ret;
  }
}

Alcune estensioni forniscono filtri per i casi di entrata/uscita dei dati, come la famiglia di DB_File::filter_store_key. Cercate filtri del genere nella documentazione delle vostre estensioni, possono rendere la transizione a Unicode molto più facile.

Velocità

Alcune funzioni sono più lente quando lavorano su stringhe codificate in UTF-8 piuttosto che su stringhe di byte. Tutte le funzioni che devono saltare caratteri, come length(), substr() o index(), lavorano molto più velocemente quando i dati sono byte. Guardate questo benchmark:

% perl -e '
use Benchmark;
use strict;
our $l = 10000;
our $u = our $b = "x" x $l;
substr($u,0,1) = "\x{100}";
timethese(-2,{
LENGTH_B => q{ length($b) },
LENGTH_U => q{ length($u) },
SUBSTR_B => q{ substr($b, $l/4, $l/2) },
SUBSTR_U => q{ substr($u, $l/4, $l/2) },
});
'
Benchmark: running LENGTH_B, LENGTH_U, SUBSTR_B, SUBSTR_U for at least 2 CPU seconds...
  LENGTH_B:  2 wallclock secs ( 2.36 usr +  0.00 sys =  2.36 CPU) @ 5649983.05/s (n=13333960)
  LENGTH_U:  2 wallclock secs ( 2.11 usr +  0.00 sys =  2.11 CPU) @ 12155.45/s (n=25648)
  SUBSTR_B:  3 wallclock secs ( 2.16 usr +  0.00 sys =  2.16 CPU) @ 374480.09/s (n=808877)
  SUBSTR_U:  2 wallclock secs ( 2.11 usr +  0.00 sys =  2.11 CPU) @ 6791.00/s (n=14329)

I numeri mostrano un'incredibile lentezza su stringhe UTF-8 lunghe. Dovreste evitare attentamente tali funzioni in cicli compatti. Se volete iterare sui caratteri, il sistema migliore è di usare split per mettere i caratteri in un array, come mostra questo benchmark:

% perl -e '
use Benchmark;
use strict;
our $l = 10000;
our $u = our $b = "x" x $l;
substr($u,0,1) = "\x{100}";
timethese(-5,{
SPLIT_B => q{ for my $c (split //, $b){}  },
SPLIT_U => q{ for my $c (split //, $u){}  },
SUBSTR_B => q{ for my $i (0..length($b)-1){my $c = substr($b,$i,1);} },
SUBSTR_U => q{ for my $i (0..length($u)-1){my $c = substr($u,$i,1);} },
});
'
Benchmark: running SPLIT_B, SPLIT_U, SUBSTR_B, SUBSTR_U for at least 5 CPU seconds...
   SPLIT_B:  6 wallclock secs ( 5.29 usr +  0.00 sys =  5.29 CPU) @ 56.14/s (n=297)
   SPLIT_U:  5 wallclock secs ( 5.17 usr +  0.01 sys =  5.18 CPU) @ 55.21/s (n=286)
  SUBSTR_B:  5 wallclock secs ( 5.34 usr +  0.00 sys =  5.34 CPU) @ 123.22/s (n=658)
  SUBSTR_U:  7 wallclock secs ( 6.20 usr +  0.00 sys =  6.20 CPU) @  0.81/s (n=5)

Anche se l'algoritmo basato su substr() è più veloce di split() nel caso di byte, scompare in confronto alla velocità di split() usato con dati UTF-8.

VEDI ANCHE

perluniintro, encoding, Encode, open, utf8, bytes, perlretut, "${^WIDE_SYSTEM_CALLS}" in perlvar