Perché il Perl moderno evita l’UTF-8 di default?

Mi chiedo perché la maggior parte delle soluzioni moderne costruite usando Perl non abilitino l’ UTF-8 di default.

Capisco che ci sono molti problemi legacy per gli script Perl di base, in cui si possono rompere le cose. Ma, dal mio punto di vista, nel 21 ° secolo, grandi nuovi progetti (o progetti con una grande prospettiva) dovrebbero rendere il loro software UTF-8 a prova da zero. Ancora non lo vedo accadere. Ad esempio, Moose triggers severi e avvisi, ma non Unicode . Modern :: Perl riduce anche il boilerplate, ma non gestisce UTF-8.

Perché? Ci sono alcuni motivi per evitare l’UTF-8 nei moderni progetti Perl nell’anno 2011?


Commentando @tchrist è arrivato troppo tempo, quindi lo aggiungo qui.

Sembra che non mi sia chiaro. Lasciami provare ad aggiungere alcune cose.

Io e Tchrist vediamo la situazione in modo simile, ma le nostre conclusioni sono completamente opposte. Sono d’accordo, la situazione con Unicode è complicata, ma questo è il motivo per cui noi (utenti e programmatori Perl) abbiamo bisogno di un certo livello (o pragma) che rende la gestione UTF-8 facile come deve essere al giorno d’oggi.

Tychrist ha indicato molti aspetti da coprire, leggerò e penserò a loro per giorni o addirittura settimane. Tuttavia, questo non è il mio punto. tchrist cerca di dimostrare che non esiste un solo modo “per abilitare UTF-8”. Non ho così tanta conoscenza da discutere con questo. Quindi, mi attengo a esempi dal vivo.

Ho giocato con Rakudo e UTF-8 era proprio lì come avevo bisogno . Non ho avuto problemi, ha funzionato. Forse ci sono alcune limitazioni in qualche modo più profonde, ma all’inizio tutto ciò che ho testato ha funzionato come mi aspettavo.

Non dovrebbe essere un objective anche il moderno Perl 5? Lo sottolineo di più: non sto suggerendo UTF-8 come set di caratteri predefinito per il core Perl, suggerisco la possibilità di triggersrlo con uno scatto per coloro che sviluppano nuovi progetti.

Un altro esempio, ma con un tono più negativo. I quadri dovrebbero rendere più facile lo sviluppo. Alcuni anni fa, ho provato i framework web, ma li ho buttati via perché “abilitare UTF-8” era così oscuro. Non ho trovato come e dove colbind il supporto Unicode. E ‘stato così dispendioso in termini di tempo che ho trovato più facile andare alla vecchia maniera. Ora ho visto che c’era una taglia per affrontare lo stesso problema con Mason 2: come rendere pulito Mason2 UTF-8? . Quindi, è un framework piuttosto nuovo, ma usarlo con UTF-8 richiede una profonda conoscenza dei suoi interni. È come un grande cartello rosso: STOP, non usare me!

Mi piace molto il Perl. Ma trattare con Unicode è doloroso. Mi trovo ancora a correre contro i muri. In qualche modo Tchrist ha ragione e risponde alle mie domande: i nuovi progetti non attirano UTF-8 perché è troppo complicato in Perl 5.


🌴 🐪🐫🐪🐫🐪 🌞 𝕲𝖔 𝕿𝖍𝖔𝖚 𝖆𝖓𝖉 𝕯𝖔 𝕷𝖎𝖐𝖊𝖜𝖎𝖘𝖊 🌞 🐁 🐁


𝓔𝓭𝓲𝓽: 𝙎𝙞𝙢𝙥𝙡𝙚𝙨𝙩 : 𝟕 𝘿𝙞𝙨𝙘𝙧𝙚𝙩𝙚 𝙍𝙚𝙘𝙤𝙢𝙢𝙚𝙣𝙙𝙖𝙩𝙞𝙤𝙣𝙨

  1. Imposta il tuo PERL_UNICODE invariato su AS . Questo fa in modo che tutti gli script Perl decodificino @ARGV come stringhe UTF-8 e imposta la codifica di tutti e tre gli stdin, stdout e stderr in UTF-8. Entrambi sono effetti globali, non lessicali.

  2. Nella parte superiore del tuo file sorgente (programma, modulo, libreria, do hickey), asserisci chiaramente che stai utilizzando perl versione 5.12 o superiore tramite:

    use v5.12; # minimal for unicode string feature

    use v5.14; # optimal for unicode string feature

  3. Abilita avvisi, poiché la dichiarazione precedente abilita solo stricture e funzionalità, non gli avvisi. Suggerisco anche di promuovere gli avvisi Unicode nelle eccezioni, quindi usa entrambe queste righe, non solo una di esse. Si noti tuttavia che sotto v5.14, la class di avvertimento utf8 comprende altri tre subwarnings che possono essere abilitati separatamente: nonchar , surrogate e non_unicode . Questi potresti desiderare di esercitare un maggiore controllo.

    use warnings;

    use warnings qw( FATAL utf8 );

  4. Dichiara che questa unità sorgente è codificata come UTF-8. Sebbene una volta questo pragma facesse altre cose, ora serve questo solo scopo singolare e nessun altro:

    use utf8;

  5. Dichiarare che tutto ciò che apre un filehandle all’interno di questo scope lessicale ma non altrove è assumere che quel stream sia codificato in UTF-8 a meno che non lo si dica diversamente. In questo modo non influisci sul codice di altri moduli o di altri programmi.

    use open qw( :encoding(UTF-8) :std );

  6. Abilita i caratteri con nome tramite \N{CHARNAME} .

    use charnames qw( :full :short );

  7. Se hai un handle DATA , devi impostare esplicitamente la sua codifica. Se vuoi che questo sia UTF-8, allora dì:

    binmode(DATA, ":encoding(UTF-8)");

Naturalmente non vi è alcuna fine di altre questioni con le quali potresti eventualmente trovarti interessato, ma queste saranno sufficienti per approssimare l’objective dello stato di “far funzionare tutto con UTF-8”, anche se per un senso un po ‘indebolito di quei termini.

Un altro pragma, anche se non è correlato a Unicode, è:

  use autodie; 

È fortemente raccomandato.


🎅 𝕹 𝖔 𝕸 𝖆 𝖌 𝖎 𝖈 𝕭 𝖚 𝖑 𝖑 𝖊 🎅


Dicendo che “Perl dovrebbe [in qualche modo! ] abilitare Unicode di default “non inizia nemmeno a pensare di andare in giro dicendo abbastanza da essere utile solo marginalmente in una specie di caso raro e isolato. Unicode è molto più di un semplice repertorio di personaggi; è anche il modo in cui tutti questi personaggi interagiscono in molti, molti modi.

Anche le semplici misure minime che (alcune) persone sembrano ritenere di volere sono garantite per infrangere miseramente milioni di righe di codice, codice che non ha possibilità di “aggiornare” la tua nuova e spensierata modernità di Brave New World .

È molto più complicato di quanto la gente finga. Ho pensato a questo enorme, molto negli ultimi anni. Mi piacerebbe essere mostrato che ho torto. Ma non penso di esserlo. L’Unicode è fondamentalmente più complesso del modello che ti piacerebbe imporre, e qui c’è complessità che non puoi mai spazzare sotto il tappeto. Se ci provi, romperesti il ​​tuo codice personale o quello di qualcun altro. Ad un certo punto, devi semplicemente abbattere e imparare di cosa tratta Unicode. Non puoi fingere che sia qualcosa che non è.

🐪 si impegna a rendere Unicode facile, molto più di qualsiasi altra cosa abbia mai usato. Se pensi che questo sia male, prova qualcos’altro per un po ‘. Quindi torna a 🐪: o sarai tornato in un mondo migliore, altrimenti porterai la conoscenza dello stesso con te in modo che possiamo usare la tua nuova conoscenza per rendere 🐪 migliore in queste cose.


💡 𝕴𝖉𝖊𝖆𝖘 𝖋𝖔𝖗 𝖆 𝖀𝖓𝖎𝖈𝖔𝖉𝖊 ⸗ 𝕬𝖜𝖆𝖗𝖊 🐪 𝕷𝖆𝖚𝖓𝖉𝖗𝖞 💡 💡


Come minimo, qui ci sono alcune cose che sembrerebbero necessarie per 🐪 per “abilitare Unicode di default”, come lo metti:

  1. Per impostazione predefinita, tutto il codice sorgente should dovrebbe essere in UTF-8. Puoi ottenerlo use utf8 o export PERL5OPTS=-Mutf8 .

  2. L’handle 🐪 DATA deve essere UTF-8. Dovrai farlo in base al pacchetto, come in binmode(DATA, ":encoding(UTF-8)") .

  3. Per impostazione predefinita, gli argomenti del programma per gli script 🐪 devono essere intesi come UTF-8. export PERL_UNICODE=A o perl -CA oppure export PERL5OPTS=-CA .

  4. Gli stream standard di input, output e error devono essere impostati su UTF-8. export PERL_UNICODE=S per tutti loro, oppure I , O , e / o E solo per alcuni di essi. Questo è come perl -CS .

  5. Eventuali altre maniglie aperte da 🐪 devono essere considerate UTF-8 se non dichiarato diversamente; export PERL_UNICODE=D o con i e o per particolari di questi; export PERL5OPTS=-CD funzionerebbe. Ciò rende -CSAD per tutti loro.

  6. Coprire entrambe le basi più tutti i flussi aperti con export PERL5OPTS=-Mopen=:utf8,:std . Vedi uniquote .

  7. Non vuoi perdere gli errori di codifica UTF-8. Prova ad export PERL5OPTS=-Mwarnings=FATAL,utf8 . E assicurati che i tuoi flussi di input siano sempre binmode da :encoding(UTF-8) , non solo per :utf8 .

  8. I punti di codice compresi tra 128 e 255 devono essere interpretati da 🐪 come punti di codice Unicode corrispondenti, non solo valori binari non gestiti. use feature "unicode_strings" o export PERL5OPTS=-Mfeature=unicode_strings . Ciò renderà uc("\xDF") eq "SS" e "\xE9" =~ /\w/ . Anche una semplice export PERL5OPTS=-Mv5.12 o superiore lo otterrà.

  9. I caratteri Unicode con nome non sono abilitati per impostazione predefinita, quindi aggiungi export PERL5OPTS=-Mcharnames=:full,:short,latin,greek o alcuni di questi. Vedi uninames e tcgrep .

  10. È quasi sempre necessario accedere alle funzioni dal modulo standard Unicode::Normalize vari tipi di scomposizioni. export PERL5OPTS=-MUnicode::Normalize=NFD,NFKD,NFC,NFKD , quindi esegui sempre le cose in arrivo tramite NFD e roba in uscita da NFC. Non esiste un livello I / O per questi, ma ne sono a conoscenza, ma vedi nfc , nfd , nfkd e nfkc .

  11. I confronti tra stringhe in 🐪 usando eq , ne , lc , cmp , sort , & c & cc sono sempre sbagliati. Quindi, anziché @a = sort @b , hai bisogno di @a = Unicode::Collate->new->sort(@b) . Potrebbe anche aggiungerlo export PERL5OPTS=-MUnicode::Collate . È ansible memorizzare la chiave nella cache per i confronti binari.

  12. 🐪 built-in come printf e write fanno la cosa sbagliata con i dati Unicode. È necessario utilizzare il modulo Unicode::GCString per il primo e sia quello che il modulo Unicode::LineBreak anche per quest’ultimo. Vedi uwc e unifmt .

  13. Se vuoi che contino come numeri interi, dovrai eseguire i tuoi \d+ acquisizioni tramite la funzione Unicode::UCD::num perché l’to built-in di atoi (3) non è attualmente abbastanza intelligente.

  14. Avrai problemi di filesystem su 👽 filesystems. Alcuni filesystem applicano silenziosamente una conversione a NFC; altri silenziosamente applicano una conversione a NFD. E altri fanno ancora qualcos’altro. Alcuni addirittura ignorano del tutto la questione, il che porta a problemi ancora più grandi. Quindi devi fare la tua manipolazione NFC / NFD per rimanere sano di mente.

  15. Tutto il tuo codice involving che comprende az o AZ e tale DEVE ESSERE MODIFICATO , inclusi m// , s/// e tr/// . Dovrebbe risaltare come una bandiera rossa urlante che il tuo codice è rotto. Ma non è chiaro come debba cambiare. Ottenere le proprietà giuste e comprenderne le fasce, è più difficile di quanto si possa pensare. Io uso unichar e uniprops ogni singolo giorno.

  16. Il codice che usa \p{Lu} è quasi sbagliato come il codice che usa [A-Za-z] . Devi invece usare \p{Upper} e conoscere il motivo per cui. Sì, \p{Lowercase} e \p{Lower} sono diversi da \p{Ll} e \p{Lowercase_Letter} .

  17. Il codice che usa [a-zA-Z] è anche peggio. E non può usare \pL o \p{Letter} ; ha bisogno di usare \p{Alphabetic} . Non tutti gli alfabetici sono lettere, lo sai!

  18. Se stai cercando 🐪 variabili con /[\$\@\%]\w+/ , allora hai un problema. Devi cercare /[\$\@\%]\p{IDS}\p{IDC}*/ , e anche questo non sta pensando alle variabili di punteggiatura o alle variabili del pacchetto.

  19. Se stai controllando la presenza di spazi vuoti, dovresti scegliere tra \h e \v , a seconda. E non dovresti mai usare \s , dal momento che NON SIGNIFICA [\h\v] , contrariamente alla credenza popolare.

  20. Se stai usando \n per un limite di linea, o anche \r\n , allora stai sbagliando. Devi usare \R , che non è lo stesso!

  21. Se non sai quando e se chiamare Unicode :: Stringprep , allora è meglio imparare.

  22. I confronti insensibili alle maiuscole e minuscole devono verificare se due cose sono le stesse lettere, indipendentemente dai loro segni diacritici e simili. Il modo più semplice per farlo è con il modulo standard Unicode :: Collate . Unicode::Collate->new(level => 1)->cmp($a, $b) . Esistono anche metodi eq , e probabilmente dovresti anche imparare i metodi match e substr . Questi hanno vantaggi distinti rispetto ai 🐪 built-in.

  23. A volte non è ancora sufficiente, e invece hai bisogno del modulo Unicode::Collate::Locale->new(locale => "de__phonebook", level => 1)->cmp($a, $b) :: Locale , come in Unicode::Collate::Locale->new(locale => "de__phonebook", level => 1)->cmp($a, $b) invece. Si consideri che Unicode::Collate::->new(level => 1)->eq("d", "ð") è vero, ma Unicode::Collate::Locale->new(locale=>"is",level => 1)->eq("d", " ð") è falso. Allo stesso modo, “ae” e “æ” sono eq se non si utilizzano le impostazioni locali o se si utilizza quella inglese, ma sono diverse nelle impostazioni locali islandesi. Ora cosa? È difficile, ti dico. Puoi giocare con ucsort per testare alcune di queste cose.

  24. Considera come abbinare il modello CVCV (consonsante, vocale, consonante, vocale) nella stringa ” niño “. La sua forma NFD – che avevi maledettamente bene ricordato di averla inserita – diventa “nin \ x {303} o”. Ora cosa stai per fare? Anche fingendo che una vocale sia [aeiou] (che è errata, comunque), non sarai in grado di fare qualcosa come (?=[aeiou])\X) , perché anche in NFD un punto di codice come ‘ ø ‘ non si decompone ! Tuttavia, testerà una “o” usando il confronto UCA che ti ho appena mostrato. Non puoi fare affidamento su NFD, devi fare affidamento su UCA.


💩 𝔸 𝕤 𝕤 𝕞 𝕖 𝕖 𝔹 𝕣 💩 💩 💩


E non è tutto. Ci sono milioni di presupposti errati che le persone fanno su Unicode. Fino a quando non capiranno queste cose, il loro codice will sarà rotto.

  1. Codice che presuppone che possa aprire un file di testo senza specificare che la codifica è interrotta.

  2. Il codice che presuppone che la codifica predefinita sia una sorta di codifica della piattaforma nativa è interrotta.

  3. Codice che presuppone che le pagine Web in giapponese o cinese occupino meno spazio in UTF-16 rispetto a UTF-8.

  4. Il codice che presuppone che Perl utilizzi UTF-8 internamente è sbagliato.

  5. Il codice che presuppone che gli errori di codifica generino sempre un’eccezione è errato.

  6. Il codice che presuppone che i punti di codice Perl sono limitati a 0x10_FFFF è errato.

  7. Il codice che presume che tu possa impostare $/ a qualcosa che funzioni con qualsiasi separatore di riga valido è sbagliato.

  8. Il codice che presuppone l’uguaglianza di roundtrip su casefolding, come lc(uc($s)) eq $s o uc(lc($s)) eq $s , è completamente rotto e sbagliato. Si consideri che uc("σ") e uc("ς") sono entrambi "Σ" , ma lc("Σ") non può possibilmente restituire entrambi.

  9. Il codice che presuppone che ogni punto in codice minuscolo abbia uno maiuscolo o minuscolo, o viceversa, è rotto. Ad esempio, "ª" è una lettera minuscola senza lettere maiuscole; mentre sia "ᵃ" che "ᴬ" sono lettere, ma non sono lettere minuscole; tuttavia, sono entrambi punti di codice minuscolo senza corrispondenti versioni maiuscole. Capito? Non sono \p{Lowercase_Letter} , nonostante siano sia \p{Letter} che \p{Lowercase} .

  10. Codice che presuppone che la modifica del caso non cambi la lunghezza della stringa è rotto.

  11. Il codice che presuppone che ci siano solo due casi è rotto. C’è anche Titlecase.

  12. Codice che presuppone che solo le lettere abbiano un caso rotto. Al di là delle sole lettere, si scopre che numeri, simboli e persino marchi hanno un caso. In effetti, cambiare il caso può anche far cambiare qualcosa nella sua categoria generale, come un \p{Mark} diventa \p{Letter} . Può anche farlo passare da uno script all’altro.

  13. Il codice che presuppone che il caso non sia mai dipendente dalle impostazioni internazionali è danneggiato.

  14. Il codice che presuppone che Unicode fornisca un esempio di localizzazione POSIX è rotto.

  15. Il codice che presume che tu possa rimuovere i segni diacritici per ottenere le lettere ASCII di base è malvagio, fermo, rotto, danneggiato dal cervello, sbagliato e giustificato per la pena capitale.

  16. Il codice che presuppone che diacritici \p{Diacritic} e segni \p{Mark} sono la stessa cosa è rotto.

  17. Il codice che presuppone \p{GC=Dash_Punctuation} copre quanto \p{Dash} è rotto.

  18. Codice che presuppone trattino, trattini e svantaggi sono la stessa cosa l’uno dell’altro, o che ce n’è solo uno, è rotto e sbagliato.

  19. Il codice che presuppone che ogni punto di codice occupa non più di una colonna di stampa è rotto.

  20. Il codice che presuppone che tutti i caratteri \p{Mark} occupino zero colonne di stampa è rotto.

  21. Codice che presuppone che i personaggi somiglianti siano rotti.

  22. Codice che presuppone che i personaggi che non si assomigliano non siano uguali è rotto.

  23. Codice che presuppone che ci sia un limite al numero di punti di codice in una riga che solo un \X può corrispondere è sbagliato.

  24. Il codice che presuppone che \X non possa mai iniziare con un carattere \p{Mark} è sbagliato.

  25. Il codice che presume che \X non possa mai contenere due caratteri non \p{Mark} è sbagliato.

  26. Il codice che presuppone che non può utilizzare "\x{FFFF}" è sbagliato.

  27. Il codice che presuppone un punto di codice non BMP che richiede due unità di codice UTF-16 (surrogato) codificherà su due caratteri UTF-8 separati, uno per unità di codice, è errato. Non lo fa: codifica per singolo punto di codice.

  28. Il codice che transcodifica da UTF-16 o UTF-32 con BOM principali in UTF-8 è interrotto se inserisce una BOM all’inizio dell’UTF-8 risultante. Questo è così stupido che l’ingegnere dovrebbe togliere le palpebre.

  29. Il codice che presuppone che il CESU-8 sia una codifica UTF valida è errato. Allo stesso modo, il codice che pensa di codificare U + 0000 come "\xC0\x80" è UTF-8 è rotto e sbagliato. Anche questi ragazzi meritano il trattamento palpebrale.

  30. Codice che presuppone che caratteri come > puntino sempre a destra e che < punti sempre a sinistra siano sbagliati - perché in effetti non lo fanno.

  31. Codice che presuppone se prima generi il carattere X e poi il carattere Y , che quelli appariranno come XY è sbagliato. A volte no.

  32. Il codice che presuppone che ASCII sia abbastanza buono per scrivere correttamente l'inglese è stupido, miope, analfabeta, infranto, malvagio e sbagliato. Fuori di testa! Se ciò sembra troppo estremo, possiamo scendere a compromessi: d'ora in poi potranno scrivere solo con il loro alluce da un piede (il resto sarà comunque tagliato).

  33. Il codice che presuppone che tutti i punti di codice di \p{Math} sono caratteri visibili è errato.

  34. Il codice che presuppone \w contiene solo lettere, cifre e caratteri di sottolineatura è errato.

  35. Codice che presuppone che ^ e ~ siano segni di punteggiatura errati.

  36. Codice che presuppone che ü abbia una dieresi errata.

  37. Il codice che crede che cose come contengano lettere in esse è sbagliato.

  38. Il codice che crede \p{InLatin} è uguale a \p{Latin} è atrocemente rotto.

  39. Il codice che crede che \p{InLatin} sia quasi sempre utile è quasi certamente sbagliato.

  40. Codice che crede che dato $FIRST_LETTER come prima lettera in qualche alfabeto e $LAST_LETTER come l'ultima lettera nello stesso alfabeto, che [${FIRST_LETTER}-${LAST_LETTER}] abbia qualche significato è quasi sempre completo, rotto e sbagliato e privo di significato.

  41. Codice che crede che il nome di qualcuno possa contenere solo determinati personaggi è stupido, offensivo e sbagliato.

  42. Il codice che tenta di ridurre Unicode in ASCII non è semplicemente sbagliato, il suo autore non dovrebbe mai essere autorizzato a lavorare di nuovo in programmazione. Periodo. Non sono nemmeno sicuro che dovrebbero essere autorizzati a vedere di nuovo, poiché ovviamente non li ha fatti molto bene finora.

  43. Il codice che crede che esista un modo per far finta che le codifiche del file di testo non esistano è rotto e pericoloso. Tanto vale colpire anche l'altro occhio.

  44. Codice che converte i caratteri sconosciuti in ? è rotto, stupido, braindead e funziona in modo contrario alla raccomandazione standard, che dice NON FARE QUELLO! RTFM per perché no.

  45. Il codice che crede di poter indovinare in modo affidabile la codifica di un file di testo non marcato è colpevole di un fatale mélange di hubris e ingenuità che solo un fulmine di Zeus risolverà.

  46. Il codice che crede di poter utilizzare 🐪 printf width per il rilievo e giustificare i dati Unicode è rotto e sbagliato.

  47. Codice che crede che una volta creato con successo un file con un nome specifico, che quando si esegue ls o readdir nella sua directory che lo racchiude, si scoprirà che quel file con il nome in cui è stato creato è bacato, rotto e sbagliato. Smettila di essere sorpreso da questo!

  48. Il codice che crede che UTF-16 sia una codifica a larghezza fissa è stupido, rotto e sbagliato. Revoca la licenza di programmazione.

  49. Il codice che tratta i punti di codice da un piano uno in modo diverso rispetto a quelli di qualsiasi altro piano è ipso facto rotto e sbagliato. Torna a scuola.

  50. Codice che crede che cose come /s/i possano corrispondere solo a "S" o "s" è rotto e sbagliato. Saresti sorpreso.

  51. Il codice che usa \PM\pM* per trovare grapheme cluster invece di usare \X è rotto e sbagliato.

  52. Le persone che vogliono tornare nel mondo ASCII dovrebbero essere incoraggiate con tutto il cuore a farlo, e in onore del loro glorioso aggiornamento dovrebbero essere fornite gratuitamente con una macchina da scrivere manuale pre-elettrica per tutte le loro esigenze di inserimento dei dati. I messaggi inviati a loro devono essere inviati tramite un telegrafo di ats a 40 caratteri per riga e consegnati a mano da un corriere. STOP.


🎁 🐪 𝕭𝖔𝖎𝖑𝖊𝖗⸗𝖕𝖑𝖆𝖙𝖊 𝖋𝖔𝖗 𝖀𝖓𝖎𝖈𝖔𝖉𝖊⸗𝕬𝖜𝖆𝖗𝖊 𝕮𝖔𝖉𝖊 🐪 🎁


Il mio boilerplate di questi giorni tende ad assomigliare a questo:

 use 5.014; use utf8; use strict; use autodie; use warnings; use warnings qw< FATAL utf8 >; use open qw< :std :utf8 >; use charnames qw< :full >; use feature qw< unicode_strings >; use File::Basename qw< basename >; use Carp qw< carp croak confess cluck >; use Encode qw< encode decode >; use Unicode::Normalize qw< NFD NFC >; END { close STDOUT } if (grep /\P{ASCII}/ => @ARGV) { @ARGV = map { decode("UTF-8", $_) } @ARGV; } $0 = basename($0); # shorter messages $| = 1; binmode(DATA, ":utf8"); # give a full stack dump on any untrapped exceptions local $SIG{__DIE__} = sub { confess "Uncaught exception: @_" unless $^S; }; # now promote run-time warnings into stackdumped exceptions # *unless* we're in an try block, in which # case just generate a clucking stackdump instead local $SIG{__WARN__} = sub { if ($^S) { cluck "Trapped warning: @_" } else { confess "Deadly warning: @_" } }; while (<>) { chomp; $_ = NFD($_); ... } continue { say NFC($_); } __END__ 

😱 𝕾 𝖀 𝕸 𝕸 𝕬 𝕽 𝖄 😱


Non so quanto più "default Unicode in 🐪" puoi ottenere rispetto a quello che ho scritto. Bene, sì lo faccio: dovresti usare anche Unicode::Collate e Unicode::LineBreak . E probabilmente di più.

Come vedi, ci sono troppe cose Unicode di cui devi davvero preoccuparti perché non esisterà mai qualcosa come "default to Unicode".

Quello che scoprirai, proprio come abbiamo fatto in 🐪 5.8, è semplicemente imansible imporre tutte queste cose su un codice che non è stato progettato fin dall'inizio per renderlo conto. Il tuo egoismo ben intenzionato ha appena infranto il mondo intero.

E anche una volta che fai, ci sono ancora problemi critici che richiedono una grande quantità di pensiero per avere ragione. Non c'è nessun interruttore che puoi capovolgere. Nient'altro che il cervello, e intendo il vero cervello , basterà qui. C'è un sacco di cose che devi imparare. Modulo il ritiro alla macchina da scrivere manuale, semplicemente non puoi sperare di sgattaiolare nell'ignoranza. Questo è il 21 ° secolo e non puoi desiderare Unicode per ignoranza intenzionale.

Devi impararlo. Periodo. Non sarà mai così facile che "tutto funziona", perché ciò garantirà che molte cose non funzionano, il che invalida l'ipotesi che possa mai esistere un modo per "far funzionare tutto".

Potresti essere in grado di ottenere alcune impostazioni predefinite ragionevoli per operazioni molto limitate e molto limitate, ma non senza pensare alle cose molto più di quanto pensi che tu abbia.

Come solo un esempio, l'ordinamento canonico causerà dei veri e propri grattacapi. 😭 "\x{F5}" 'õ' , "o\x{303}" 'õ' , "o\x{303}\x{304}" 'ȭ' e "o\x{304}\x{303}" 'ō' dovrebbe tutti corrispondere 'õ' , ma come mai nel mondo hai intenzione di farlo? È più difficile di quanto sembri, ma è qualcosa che devi rendere conto. 💣

Se c'è una cosa che so di Perl, è ciò che i suoi bit Unicode fanno e non fanno, e questa cosa ti prometto: "ᴛʜᴇʀᴇ ɪs ɴᴏ Uɴɪᴄᴏᴅᴇ ᴍᴀɢɪᴄ ʙᴜʟʟᴇᴛ" 😞

Non è ansible modificare alcune impostazioni predefinite e ottenere una navigazione fluida. È vero che eseguo 🐪 con PERL_UNICODE impostato su "SA" , ma questo è tutto, e anche questo è principalmente per roba da linea di comando. Per il vero lavoro, passo attraverso tutti i molti passaggi descritti sopra, e lo faccio molto, ** molto ** attentamente.


Ƨ ¡ƨdləɥ ƨᴉɥʇ ədoɥ puɐ'λɐp əɔᴉu ɐ əʌɐɥ'ʞɔnl poo⅁ 😈

Ci sono due fasi per l’elaborazione del testo Unicode. Il primo è “come posso inserirlo e inviarlo senza perdere informazioni”. Il secondo è “come posso trattare il testo secondo le convenzioni della lingua locale”.

Il post di tchrist copre entrambi, ma la seconda parte è da dove proviene il 99% del testo nel suo post. La maggior parte dei programmi non gestisce nemmeno l’I / O in modo corretto, quindi è importante capirlo prima ancora di iniziare a preoccuparsi della normalizzazione e delle regole di confronto.

Questo post mira a risolvere questo primo problema

Quando leggi i dati in Perl, non gli importa quale sia la codifica. Assegna un po ‘di memoria e nasconde i byte. Se si dice print $str , questo blocca quei byte sul terminale, che probabilmente è impostato per assumere tutto ciò che è scritto su di esso è UTF-8 e il testo appare.

Meravigliosa.

Tranne, non lo è. Se cerchi di trattare i dati come testo, vedrai che sta succedendo qualcosa di brutto. Non devi andare oltre la length per vedere che cosa pensa Perl della tua stringa e cosa ne pensi della tua stringa non è d’accordo. Scrivi un one-liner come: perl -E 'while(<>){ chomp; say length }' perl -E 'while(<>){ chomp; say length }' e digita 文字化け e ottieni 12 … non la risposta corretta, 4.

Questo perché Perl assume che la tua stringa non sia un testo. Devi dire che è un testo prima che ti dia la risposta giusta.

È abbastanza facile; il modulo Encode ha le funzioni per farlo. Il punto di ingresso generico è Encode::decode (o use Encode qw(decode) , ovviamente). Quella funzione prende una stringa dal mondo esterno (quello che chiameremo “ottetti”, un modo di dire “byte a 8 bit”), e lo trasforma in un testo che Perl capirà. Il primo argomento è un nome di codifica dei caratteri, come “UTF-8” o “ASCII” o “EUC-JP”. Il secondo argomento è la stringa. Il valore restituito è lo scalare Perl contenente il testo.

(C’è anche Encode::decode_utf8 , che presuppone UTF-8 per la codifica.)

Se riscriviamo il nostro one-liner:

 perl -MEncode=decode -E 'while(<>){ chomp; say length decode("UTF-8", $_) }' 

Digitiamo 文字 化 け e otteniamo “4” come risultato. Successo.

Questo, proprio lì, è la soluzione al 99% dei problemi Unicode in Perl.

La chiave è che ogni volta che un testo entra nel tuo programma, devi decodificarlo. Internet non può trasmettere caratteri. I file non possono memorizzare caratteri. Non ci sono caratteri nel tuo database. Ci sono solo ottetti e non puoi trattare gli ottetti come caratteri in Perl. Devi decodificare gli ottetti codificati in caratteri Perl con il modulo Encode.

L’altra metà del problema è ottenere dati dal tuo programma. È facile; dici solo use Encode qw(encode) , decidere in che modo verranno codificati i tuoi dati (UTF-8 ai terminali che comprendono UTF-8, UTF-16 per i file su Windows, ecc.), quindi emettere il risultato della encode($encoding, $data) invece di emettere solo $data .

Questa operazione converte i caratteri di Perl, su cui opera il tuo programma, in ottetti che possono essere usati dal mondo esterno. Sarebbe molto più semplice se potessimo semplicemente inviare caratteri su Internet o sui nostri terminali, ma non possiamo: solo gli ottetti. Quindi dobbiamo convertire i caratteri in ottetti, altrimenti i risultati non sono definiti.

Per riassumere: codifica tutti gli output e decodifica tutti gli input.

Ora parleremo di tre problemi che rendono questo un po ‘impegnativo. Il primo sono le librerie. Gestiscono correttamente il testo? La risposta è … ci provano. Se si scarica una pagina Web, LWP restituirà i risultati come testo. Se si chiama il metodo giusto sul risultato, vale a dire (e questo è decoded_content , non content , che è solo il stream ottetto che ha ottenuto dal server.) I driver del database possono essere instabili; se usi DBD :: SQLite con solo Perl, funzionerà, ma se qualche altro strumento ha messo il testo memorizzato come codifica diversa da UTF-8 nel tuo database … beh … non verrà gestito correttamente finché non si scrive codice per gestirlo correttamente.

L’output dei dati è solitamente più semplice, ma se vedi “caratteri grandi in stampa”, sai che stai incasinando la codifica da qualche parte. Questo avvertimento significa “hey, stai cercando di far trapelare personaggi di Perl al mondo esterno e questo non ha senso”. Il tuo programma sembra funzionare (perché l’altra estremità di solito gestisce correttamente i caratteri Perl grezzi), ma è molto rotto e potrebbe smettere di funzionare in qualsiasi momento. Risolvilo con una Encode::encode esplicita!

Il secondo problema è il codice sorgente codificato in UTF-8. A meno che tu non use utf8 nella parte superiore di ogni file, Perl non presumerà che il tuo codice sorgente sia UTF-8. Ciò significa che ogni volta che dici qualcosa come il my $var = 'ほげ' , stai immettendo immondizie nel tuo programma che interromperà completamente tutto in modo orribile. Non è necessario “usare utf8”, ma in caso contrario, non è necessario utilizzare caratteri non ASCII nel programma.

Il terzo problema è come Perl gestisce The Past. Molto tempo fa, non esisteva nulla come Unicode, e Perl pensava che tutto fosse latino-1 testo o binario. Quindi quando i dati arrivano nel tuo programma e inizi a trattarli come testo, Perl tratta ogni ottetto come un carattere Latin-1. Ecco perché, quando abbiamo chiesto la lunghezza di “文字 化 け”, abbiamo ottenuto 12. Perl ha supposto che stessimo operando sulla stringa Latin-1 “æååã” (che è di 12 caratteri, alcuni dei quali non stampabili).

Questo è chiamato “upgrade implicito” ed è una cosa perfettamente ragionevole da fare, ma non è quello che vuoi se il tuo testo non è Latin-1. Ecco perché è fondamentale decodificare in modo esplicito l’input: se non lo fai, Perl lo farà, e potrebbe sbagliare.

Le persone si imbattono in problemi in cui metà dei loro dati è una stringa di caratteri corretta e alcuni sono ancora binari. Perl interpreterà la parte che è ancora binaria come se fosse un testo Latin-1 e quindi combinata con i dati di carattere corretti. In questo modo sembrerà che gestire i tuoi personaggi abbia rotto correttamente il tuo programma, ma in realtà non lo hai risolto abbastanza.

Ecco un esempio: si dispone di un programma che legge un file di testo con codifica UTF-8, si affina su un Unicode PILE OF POO su ogni riga e lo si stampa. Lo scrivi come:

 while(<>){ chomp; say "$_ 💩"; } 

E quindi eseguire su alcuni dati codificati UTF-8, come:

 perl poo.pl input-data.txt 

Stampa i dati UTF-8 con una cacca alla fine di ogni riga. Perfetto, il mio programma funziona!

Ma no, stai solo facendo concatenazione binaria. Stai leggendo gli ottetti dal file, rimuovendo un \n con il chomp e poi incollando i byte nella rappresentazione UTF-8 del carattere PILE OF POO . Quando rivedi il tuo programma per decodificare i dati dal file e codificare l’output, noterai che ottieni la spazzatura (“ð ©”) invece della cacca. Questo ti porterà a credere che decodificare il file di input sia la cosa sbagliata da fare. Non è.

Il problema è che la cacca viene implicitamente aggiornata come latin-1. Se use utf8 per creare il testo letterale invece di binario, funzionerà di nuovo!

(Questo è il problema numero uno che vedo quando aiuto le persone con Unicode. Hanno fatto bene e hanno rotto il loro programma. Questo è ciò che è triste per i risultati non definiti: puoi avere un programma di lavoro per un lungo periodo, ma quando inizi a ripararlo, Non ti preoccupare, se aggiungi al tuo programma le istruzioni di codifica / decodifica e si interrompe, significa solo che hai ancora del lavoro da fare. La prossima volta, quando progetti in anticipo con Unicode, sarà molto più facile!)

Questo è tutto ciò che devi sapere su Perl e Unicode. Se dici a Perl quali sono i tuoi dati, ha il miglior supporto Unicode tra tutti i linguaggi di programmazione più diffusi. Se si presuppone che saprà magicamente che tipo di testo si sta alimentando, però, si sta per cestinare i dati irrevocabilmente. Solo perché il tuo programma funziona oggi sul tuo terminale UTF-8 non significa che funzionerà domani su un file con codifica UTF-16. Quindi mettilo al sicuro ora e risparmia il malinteso di cestinare i dati dei tuoi utenti!

La parte facile di gestire Unicode è codificare l’input di output e decodifica. La parte difficile è trovare tutti i tuoi input e output e determinare quale codifica è. Ma è per questo che ottieni un sacco di soldi 🙂

Siamo tutti d’accordo sul fatto che si tratta di un problema difficile per molte ragioni, ma è proprio questo il motivo per cercare di renderlo più facile a tutti.

C’è un modulo recente su CPAN, utf8 :: all , che tenta di “accendere Unicode. Tutto”.

Come è stato sottolineato, non è ansible creare magicamente l’intero sistema (programmi esterni, richieste Web esterne, ecc.) Anche con Unicode, ma possiamo lavorare insieme per creare strumenti sensati che rendano più facile fare problemi comuni. Questa è la ragione per cui siamo programmatori.

Se utf8 :: all non fa qualcosa che pensi che dovrebbe, miglioriamolo per renderlo migliore. Or let’s make additional tools that together can suit people’s varying needs as well as possible.

`

I think you misunderstand Unicode and its relationship to Perl. No matter which way you store data, Unicode, ISO-8859-1 , or many other things, your program has to know how to interpret the bytes it gets as input (decoding) and how to represent the information it wants to output (encoding). Get that interpretation wrong and you garble the data. There isn’t some magic default setup inside your program that’s going to tell the stuff outside your program how to act.

You think it’s hard, most likely, because you are used to everything being ASCII. Everything you should have been thinking about was simply ignored by the programming language and all of the things it had to interact with. If everything used nothing but UTF-8 and you had no choice, then UTF-8 would be just as easy. But not everything does use UTF-8. For instance, you don’t want your input handle to think that it’s getting UTF-8 octets unless it actually is, and you don’t want your output handles to be UTF-8 if the thing reading from them can handle UTF-8. Perl has no way to know those things. That’s why you are the programmer.

I don’t think Unicode in Perl 5 is too complicated. I think it’s scary and people avoid it. There’s a difference. To that end, I’ve put Unicode in Learning Perl, 6th Edition , and there’s a lot of Unicode stuff in Effective Perl Programming . You have to spend the time to learn and understand Unicode and how it works. You’re not going to be able to use it effectively otherwise.

While reading this thread, I often get the impression that people are using ” UTF-8 ” as a synonym to ” Unicode “. Please make a distinction between Unicode’s “Code-Points” which are an enlarged relative of the ASCII code and Unicode’s various “encodings”. And there are a few of them, of which UTF-8, UTF-16 and UTF-32 are the current ones and a few more are obsolete.

Please, UTF-8 (as well as all other encodings ) exists and have meaning in input or in output only. Internally, since Perl 5.8.1, all strings are kept as Unicode “Code-points”. True, you have to enable some features as admiringly covered previously.

There’s a truly horrifying amount of ancient code out there in the wild, much of it in the form of common CPAN modules. I’ve found I have to be fairly careful enabling Unicode if I use external modules that might be affected by it, and am still trying to identify and fix some Unicode-related failures in several Perl scripts I use regularly (in particular, iTiVo fails badly on anything that’s not 7-bit ASCII due to transcoding issues).

You should enable the unicode strings feature, and this is the default if you use v5.14;

You should not really use unicode identifiers esp. for foreign code via utf8 as they are insecure in perl5, only cperl got that right. See eg http://perl11.org/blog/unicode-identifiers.html

Regarding utf8 for your filehandles/streams: You need decide by yourself the encoding of your external data. A library cannot know that, and since not even libc supports utf8, proper utf8 data is rare. There’s more wtf8, the windows aberration of utf8 around.

BTW: Moose is not really “Modern Perl”, they just hijacked the name. Moose is perfect Larry Wall-style postmodern perl mixed with Bjarne Stroustrup-style everything goes, with an eclectic aberration of proper perl6 syntax, eg using strings for variable names, horrible fields syntax, and a very immature naive implementation which is 10x slower than a proper implementation. cperl and perl6 are the true modern perls, where form follows function, and the implementation is reduced and optimized.