Je me demande pourquoi la plupart des solutions modernes construites à l'aide de Perl n'activent pas UTF-8 par défaut.
Je comprends qu'il existe de nombreux problèmes hérités pour les scripts Perl de base, où cela peut casser les choses. Mais, de mon point de vue, au 21ème siècle, les grands nouveaux projets (ou projets avec une grande perspective) devraient faire de leur logiciel UTF-8 une preuve à partir de zéro. Je ne vois toujours pas cela se produire. Par exemple, Moose active les avertissements stricts et non Unicode . Modern :: Perl réduit également le passe-partout, mais pas de manipulation UTF-8.
Pourquoi? Y a-t-il des raisons d'éviter l'UTF-8 dans les projets Perl modernes en 2011?
Commenter @tchrist est devenu trop long, alors je l'ajoute ici.
Il semble que je n'ai pas été clair. Permettez-moi d'essayer d'ajouter quelques éléments.
Tchrist et moi voyons la situation de façon assez similaire, mais nos conclusions sont complètement opposées. Je suis d'accord, la situation avec Unicode est compliquée, mais c'est pourquoi nous (utilisateurs Perl et codeurs) avons besoin d'une couche (ou pragma) qui rend la gestion UTF-8 aussi simple qu'elle doit l'être de nos jours.
tchrist a souligné de nombreux aspects à couvrir, je vais les lire et y réfléchir pendant des jours, voire des semaines. Pourtant, ce n'est pas mon point. tchrist essaie de prouver qu'il n'y a pas une seule façon "d'activer UTF-8". Je n'ai pas tellement de connaissances pour contester cela. Donc, je m'en tiens à des exemples vivants.
J'ai joué avec Rakudo et UTF-8 était juste là comme j'avais besoin . Je n'ai eu aucun problème, cela a juste fonctionné. Peut-être qu'il y a des limites quelque part plus profondément, mais au début, tout ce que j'ai testé a fonctionné comme je m'y attendais.
Cela ne devrait-il pas aussi être un objectif dans Perl 5 moderne? J'insiste davantage: je ne suggère pas UTF-8 comme jeu de caractères par défaut pour le noyau Perl, je suggère la possibilité de le déclencher avec un clin d' œil pour ceux qui développent de nouveaux projets.
Un autre exemple, mais avec un ton plus négatif. Les cadres devraient faciliter le développement. Il y a quelques années, j'ai essayé des frameworks Web, mais je les ai simplement jetés parce que "activer UTF-8" était tellement obscur. Je n'ai pas trouvé comment et où accrocher le support Unicode. Cela prenait tellement de temps que j'ai trouvé plus facile de suivre l'ancienne voie. Maintenant, j'ai vu ici qu'il y avait une prime pour faire face au même problème avec Mason 2: Comment nettoyer Mason2 UTF-8? . C'est donc un cadre assez nouveau, mais son utilisation avec UTF-8 nécessite une connaissance approfondie de ses composants internes. C'est comme un grand panneau rouge: STOP, ne m'utilise pas!
J'aime vraiment Perl. Mais traiter avec Unicode est douloureux. Je me retrouve toujours à courir contre les murs. D'une certaine manière, tchrist a raison et répond à mes questions: les nouveaux projets n'attirent pas l'UTF-8 car c'est trop compliqué dans Perl 5.
Réponses:
𝙎𝙞𝙢𝙥𝙡𝙚𝙨𝙩 ℞ : 𝟕 𝘿𝙞𝙨𝙘𝙧𝙚𝙩𝙚 𝙍𝙚𝙘𝙤𝙢𝙢𝙚𝙣𝙙𝙖𝙩𝙞𝙤𝙣𝙨
Réglez votre
PERL_UNICODE
envariable surAS
. Cela décode tous les scripts Perl@ARGV
en chaînes UTF-8 et définit le codage des trois stdin, stdout et stderr sur UTF-8. Ces deux effets sont globaux et non lexicaux.En haut de votre fichier source (programme, module, bibliothèque,
do
suçon), assurez-vous que vous exécutez perl version 5.12 ou mieux via:Activez les avertissements, car la déclaration précédente n'active que les restrictions et les fonctionnalités, pas les avertissements. Je suggère également de promouvoir les avertissements Unicode en exceptions, alors utilisez ces deux lignes, pas seulement l'une d'entre elles. Notez cependant que sous v5.14, la
utf8
classe d'avertissement comprend trois autres subwarnings qui peuvent tous être séparément activé:nonchar
,surrogate
etnon_unicode
. Vous pourriez souhaiter exercer un plus grand contrôle sur ces éléments.Déclarez que cette unité source est codée en UTF-8. Bien qu'il fut un temps où ce pragma faisait autre chose, il sert maintenant ce seul but singulier et aucun autre:
Déclarez que tout ce qui ouvre un descripteur de fichier dans cette portée lexicale, mais pas ailleurs, suppose que ce flux est codé en UTF-8, sauf indication contraire. De cette façon, vous n'affectez pas le code d'un autre module ou d'un autre programme.
Activez les caractères nommés via
\N{CHARNAME}
.Si vous avez un
DATA
handle, vous devez définir explicitement son encodage. Si vous voulez que ce soit UTF-8, alors dites:Il n'y a bien sûr pas de fin à d'autres questions qui pourraient éventuellement vous préoccuper, mais celles-ci suffiront à rapprocher l'objectif de l'État de «tout faire fonctionner avec l'UTF-8», bien que pour un sens quelque peu affaibli de ces termes.
Un autre pragma, bien qu'il ne soit pas lié à Unicode, est:
C'est fortement recommandé.
🌴 🐪🐫🐪 🌞 𝕲𝖔 𝕿𝖍𝖔𝖚 𝖆𝖓𝖉 𝕯𝖔 𝕷𝖎𝖐𝖊𝖜𝖎𝖘𝖊 🌞 🐪🐫🐪 🐁
🎁 🐪 𝕭𝖔𝖎𝖑𝖊𝖗⸗𝖕𝖑𝖆𝖙𝖊 𝖋𝖔𝖗 𝖀𝖓𝖎𝖈𝖔𝖉𝖊⸗𝕬𝖜𝖆𝖗𝖊 𝕮𝖔𝖉𝖊 🐪 🎁
Ces jours-ci, mon propre passe-partout a tendance à ressembler à ceci:
🎅 𝕹 𝖔 𝕸 𝖆 𝖌 𝖎 𝖈 𝕭 𝖚 𝖑 𝖑 𝖊 𝖙 🎅
Dire que «Perl devrait [ quelque sorte! ] Activer Unicode par défaut »ne commence même pas à commencer à penser à en dire assez pour être même marginalement utile dans une sorte de cas rare et isolé. Unicode est bien plus qu'un simple répertoire de caractères plus vaste; c'est aussi la façon dont ces personnages interagissent tous de nombreuses façons.
Même les mesures minimales simples que (certaines) personnes semblent penser vouloir sont garanties de briser misérablement des millions de lignes de code, du code qui n'a aucune chance de «mettre à niveau» vers votre nouveau style modernité courageuse Brave New World .
C'est beaucoup plus compliqué que ce que les gens prétendent. J'y ai beaucoup pensé ces dernières années. J'aimerais qu'on me montre que j'ai tort. Mais je ne pense pas que je le suis. Unicode est fondamentalement plus complexe que le modèle que vous souhaitez lui imposer, et il y a ici une complexité que vous ne pouvez jamais balayer sous le tapis. Si vous essayez, vous casserez votre propre code ou celui de quelqu'un d'autre. À un moment donné, il vous suffit de vous décomposer et de savoir de quoi parle Unicode. Vous ne pouvez pas prétendre que ce n'est pas quelque chose.
🐪 fait tout son possible pour rendre Unicode facile, bien plus que tout ce que j'ai jamais utilisé. Si vous pensez que c'est mauvais, essayez autre chose pendant un moment. Revenez ensuite à 🐪: soit vous serez retourné dans un monde meilleur, soit vous en apporterez la connaissance afin que nous puissions utiliser vos nouvelles connaissances pour améliorer 🐪 dans ces domaines.
💡 𝕴𝖉𝖊𝖆𝖘 𝖋𝖔𝖗 𝖆 𝖀𝖓𝖎𝖈𝖔𝖉𝖊 ⸗ 𝕬𝖜𝖆𝖗𝖊 🐪 𝕷𝖆𝖚𝖓𝖉𝖗𝖞 𝕷𝖎𝖘𝖙 💡
Au minimum, voici certaines choses qui semblent nécessaires pour que 🐪 "active Unicode par défaut", comme vous le dites:
Tout 🐪 le code source doit être en UTF-8 par défaut. Vous pouvez l'obtenir avec
use utf8
ouexport PERL5OPTS=-Mutf8
.La
DATA
poignée should doit être en UTF-8. Vous devrez le faire sur une base par paquet, comme dansbinmode(DATA, ":encoding(UTF-8)")
.Les arguments du programme pour les scripts 🐪 doivent être compris comme étant UTF-8 par défaut.
export PERL_UNICODE=A
, ouperl -CA
, ouexport PERL5OPTS=-CA
.Les flux d'entrée, de sortie et d'erreur standard doivent par défaut être UTF-8.
export PERL_UNICODE=S
pour chacun d'entre eux, ouI
,O
et / ouE
pour seulement certains d'entre eux. C'est commeperl -CS
.Toute autre poignée ouverte par 🐪 doit être considérée comme UTF-8, sauf indication contraire;
export PERL_UNICODE=D
ou aveci
eto
pour certains d'entre eux;export PERL5OPTS=-CD
travaillerait. Qui fait-CSAD
pour chacun d'eux.Couvrez les deux bases ainsi que tous les flux avec lesquels vous ouvrez
export PERL5OPTS=-Mopen=:utf8,:std
. Voir uniquote .Vous ne voulez pas manquer des erreurs d'encodage UTF-8. Essayez
export PERL5OPTS=-Mwarnings=FATAL,utf8
. Et assurez-vous que vos flux d'entrée sont toujoursbinmode
vers:encoding(UTF-8)
, pas seulement vers:utf8
.Les points de code compris entre 128 et 255 doivent être compris par 🐪 comme étant les points de code Unicode correspondants, et pas seulement des valeurs binaires non approuvées.
use feature "unicode_strings"
ouexport PERL5OPTS=-Mfeature=unicode_strings
. Cela ferauc("\xDF") eq "SS"
et"\xE9" =~ /\w/
. Un simpleexport PERL5OPTS=-Mv5.12
ou meilleur obtiendra également cela.Les caractères Unicode nommés ne sont pas activés par défaut, alors ajoutez-en
export PERL5OPTS=-Mcharnames=:full,:short,latin,greek
ou certains. Voir uninames et tcgrep .Vous avez presque toujours besoin d'accéder aux fonctions du module standard de
Unicode::Normalize
divers types de décompositions.export PERL5OPTS=-MUnicode::Normalize=NFD,NFKD,NFC,NFKD
, puis exécutez toujours les éléments entrants via NFD et les éléments sortants à partir de NFC. Il n'y a pas encore de couche d'E / S pour celles-ci à ma connaissance, mais voir nfc , nfd , nfkd et nfkc .Les comparaisons de chaînes à l' aide 🐪
eq
,ne
,lc
,cmp
,sort
, etc. & cc ont toujours tort. Donc, au lieu de@a = sort @b
, vous avez besoin@a = Unicode::Collate->new->sort(@b)
. Autant ajouter cela à votreexport PERL5OPTS=-MUnicode::Collate
. Vous pouvez mettre en cache la clé pour les comparaisons binaires.🐪 les modules intégrés aiment
printf
etwrite
font la mauvaise chose avec les données Unicode. Vous devez utiliser leUnicode::GCString
module pour le premier, et à la fois cela et aussi leUnicode::LineBreak
module pour le second. Voir uwc et unifmt .Si vous voulez qu'ils comptent comme des entiers, alors vous devrez exécuter vos
\d+
captures via laUnicode::UCD::num
fonction car atoi (3) intégré à isn't n'est pas actuellement assez intelligent.Vous allez avoir des problèmes de système de fichiers sur les systèmes de fichiers. Certains systèmes de fichiers appliquent silencieusement une conversion en NFC; d'autres appliquent silencieusement une conversion à NFD. Et d'autres font encore autre chose. Certains ignorent même complètement la question, ce qui entraîne des problèmes encore plus graves. Vous devez donc faire votre propre manipulation NFC / NFD pour rester sain d'esprit.
Tous vos 🐪 impliquant le code
a-z
ouA-Z
et tel doit être CHANGÉ , y comprism//
,s///
ettr///
. Il devrait ressortir comme un drapeau rouge hurlant que votre code est cassé. Mais il n'est pas clair comment cela doit changer. Obtenir les bonnes propriétés et comprendre leurs dossiers est plus difficile que vous ne le pensez. J'utilise des unichars et uniprops tous les jours.Le code qui utilise
\p{Lu}
est presque aussi faux que le code qui utilise[A-Za-z]
. Vous devez utiliser à la\p{Upper}
place et connaître la raison. Oui,\p{Lowercase}
et\p{Lower}
sont différents de\p{Ll}
et\p{Lowercase_Letter}
.Code qui utilise
[a-zA-Z]
est encore pire. Et il ne peut pas utiliser\pL
ou\p{Letter}
; il doit utiliser\p{Alphabetic}
. Tous les alphabétiques ne sont pas des lettres, vous savez!Si vous recherchez 🐪 variables avec
/[\$\@\%]\w+/
, alors vous avez un problème. Vous devez rechercher/[\$\@\%]\p{IDS}\p{IDC}*/
, et même cela ne pense pas aux variables de ponctuation ou aux variables de package.Si vous recherchez des espaces, vous devez choisir entre
\h
et\v
, selon. Et vous ne devriez jamais utiliser\s
, car cela NE SIGNIFIE PAS[\h\v]
, contrairement à la croyance populaire.Si vous utilisez
\n
pour une limite de ligne, ou même\r\n
, alors vous le faites mal. Vous devez utiliser\R
, ce qui n'est pas la même chose!Si vous ne savez pas quand et si vous devez appeler Unicode :: Stringprep , vous feriez mieux d'apprendre.
Les comparaisons insensibles à la casse doivent vérifier si deux choses sont les mêmes lettres, peu importe leurs signes diacritiques et autres. La façon la plus simple de le faire est d' utiliser le module Unicode :: Collate standard .
Unicode::Collate->new(level => 1)->cmp($a, $b)
. Il existe également deseq
méthodes et autres, et vous devriez probablement aussi en apprendre davantage sur les méthodesmatch
etsubstr
. Ce sont des avantages distincts par rapport aux 🐪 intégrés.Parfois, ce n'est toujours pas suffisant, et vous avez plutôt besoin du module Unicode :: Collate :: Locale , comme dans
Unicode::Collate::Locale->new(locale => "de__phonebook", level => 1)->cmp($a, $b)
plutôt. Considérez queUnicode::Collate::->new(level => 1)->eq("d", "ð")
c'est vrai, maisUnicode::Collate::Locale->new(locale=>"is",level => 1)->eq("d", " ð")
c'est faux. De même, "ae" et "æ" sonteq
si vous n'utilisez pas de paramètres régionaux, ou si vous utilisez l'anglais, mais ils sont différents dans les paramètres régionaux islandais. Maintenant quoi? C'est difficile, je vous le dis. Vous pouvez jouer avec ucsort pour tester certaines de ces choses.Considérez comment faire correspondre le modèle CVCV (consonne, voyelle, consonne, voyelle) dans la chaîne « niño ». Sa forme NFD - que vous aviez bien mieux sacrée avoir pensé à mettre - devient "nin \ x {303} o". Maintenant que vas-tu faire? Même en prétendant qu'une voyelle est
[aeiou]
(ce qui est faux d'ailleurs), vous ne pourrez pas faire quelque chose comme ça(?=[aeiou])\X)
non plus, car même dans NFD un point de code comme 'ø' ne se décompose pas ! Cependant, il sera testé égal à un «o» en utilisant la comparaison UCA que je viens de vous montrer. Vous ne pouvez pas compter sur NFD, vous devez compter sur UCA.💩 𝔸 𝕤 𝕤 𝕦 𝕞 𝕖 𝔹 𝕣 𝕠 𝕜 𝕖 𝕟 𝕟 𝕖 𝕤 𝕤 💩
Et ce n'est pas tout. Il y a un million d'hypothèses brisées que les gens font à propos d'Unicode. Jusqu'à ce qu'ils comprennent ces choses, leur code 🐪 sera cassé.
Le code qui suppose qu'il peut ouvrir un fichier texte sans spécifier l'encodage est rompu.
Le code qui suppose que l'encodage par défaut est une sorte d'encodage de plate-forme native est rompu.
Le code qui suppose que les pages Web en japonais ou en chinois occupent moins d'espace en UTF-16 qu'en UTF-8 est incorrect.
Le code qui suppose que Perl utilise UTF-8 en interne est incorrect.
Le code qui suppose que les erreurs de codage déclenchent toujours une exception est incorrect.
Le code qui suppose que les points de code Perl sont limités à 0x10_FFFF est incorrect.
Le code qui suppose que vous pouvez définir
$/
quelque chose qui fonctionnera avec n'importe quel séparateur de ligne valide est incorrect.Le code qui suppose l'égalité aller-retour sur le dossier, comme
lc(uc($s)) eq $s
ouuc(lc($s)) eq $s
, est complètement rompu et incorrect. Considérez que leuc("σ")
etuc("ς")
sont les deux"Σ"
, maislc("Σ")
ne peuvent pas renvoyer les deux.Le code qui suppose que chaque point de code en minuscule en a un distinct en majuscule, ou vice versa, est rompu. Par exemple,
"ª"
est une lettre minuscule sans majuscule; considérant que les deux"ᵃ"
et"ᴬ"
sont des lettres, mais ce ne sont pas des lettres minuscules; cependant, ce sont deux points de code en minuscules sans versions majuscules correspondantes. C'est compris? Ils ne le sont pas\p{Lowercase_Letter}
, bien qu'ils soient à la fois\p{Letter}
et\p{Lowercase}
.Le code qui suppose de changer la casse ne change pas la longueur de la chaîne est rompu.
Le code qui suppose qu'il n'y a que deux cas est cassé. Il y a aussi le titlecase.
Le code qui suppose que seules les lettres ont la casse est cassé. Au-delà des lettres, il s'avère que les chiffres, les symboles et même les marques ont de la casse. En fait, changer le boîtier peut même faire changer quelque chose à sa principale catégorie générale, comme le
\p{Mark}
transformer en a\p{Letter}
. Il peut également le faire passer d'un script à un autre.Le code qui suppose que la casse n'est jamais dépendante des paramètres régionaux est rompu.
Le code qui suppose qu'Unicode donne une figure sur les locales POSIX est cassé.
Le code qui suppose que vous pouvez supprimer les signes diacritiques pour obtenir les lettres ASCII de base est mauvais, immobile, cassé, endommagé au cerveau, faux et justifie la peine capitale.
Le code qui suppose que les signes diacritiques
\p{Diacritic}
et les marques\p{Mark}
sont la même chose est rompu.Code qui suppose
\p{GC=Dash_Punctuation}
couvre autant que\p{Dash}
est cassé.Le code qui suppose que les tirets, les tirets et les inconvénients sont identiques les uns aux autres, ou qu'il n'y en a qu'un seul, est cassé et incorrect.
Le code qui suppose que chaque point de code occupe plus d'une colonne d'impression est rompu.
Code qui suppose que tous
\p{Mark}
caractères occupent zéro colonne d'impression est rompu.Code qui suppose que les caractères qui se ressemblent sont brisés.
Code qui suppose que les caractères qui ne se ressemblent pas ne le sont pas identiques est cassé.
Code qui suppose qu'il y a une limite au nombre de points de code dans une ligne qu'un seul
\X
peut correspondre est incorrect.Un code qui suppose
\X
ne peut jamais commencer par un\p{Mark}
caractère est incorrect.Le code qui suppose qu'il
\X
ne peut jamais contenir deux\p{Mark}
caractères non est incorrect.Le code qui suppose qu'il ne peut pas utiliser
"\x{FFFF}"
est incorrect.Le code qui suppose un point de code non BMP qui nécessite deux unités de code UTF-16 (de substitution) sera codé en deux caractères UTF-8 distincts, un par unité de code, est incorrect. Ce n'est pas le cas: il code en un seul point de code.
Le code qui transcode UTF ‐ 16 ou UTF ‐ 32 avec les nomenclatures principales en UTF ‐ 8 est rompu s'il place une nomenclature au début de l'UTF-8 résultant. C'est tellement stupide que l'ingénieur devrait se faire enlever les paupières.
Le code qui suppose que le CESU-8 est un codage UTF valide est incorrect. De même, le code qui considère le codage U + 0000 comme
"\xC0\x80"
UTF-8 est cassé et incorrect. Ces gars-là méritent également le traitement des paupières.Le code qui suppose que les caractères comme
>
pointe toujours vers la droite et<
pointe toujours vers la gauche est faux - car ils ne le font pas.Code qui suppose que si vous sortez d'abord un caractère
X
puis un caractèreY
, ceux-ci apparaîtront commeXY
étant faux. Parfois non.Le code qui suppose que l'ASCII est assez bon pour écrire correctement l'anglais est stupide, myope, illettré, brisé, mauvais et mauvais. Enlevez leur têtes! Si cela semble trop extrême, nous pouvons faire des compromis: désormais ils ne peuvent taper qu'avec leur gros orteil d'un pied. (Le reste sera scotché.)
Le code qui suppose que tous les
\p{Math}
points de code sont des caractères visibles est incorrect.Le code qui suppose
\w
ne contient que des lettres, des chiffres et des traits de soulignement est incorrect.Le code qui suppose que
^
et~
sont des signes de ponctuation est incorrect.Le code qui suppose qu'il
ü
a un tréma est incorrect.Le code qui croit que des choses comme
₨
contenir des lettres sont incorrectes.Le code qui croit
\p{InLatin}
est le même que celui qui\p{Latin}
est abominablement brisé.Code qui croit que
\p{InLatin}
c'est presque toujours utile est presque certainement faux.Un code qui croit que donné
$FIRST_LETTER
comme première lettre d'un alphabet et$LAST_LETTER
comme dernière lettre de ce même alphabet, qui[${FIRST_LETTER}-${LAST_LETTER}]
a une signification quelconque est presque toujours complet, rompu, faux et vide de sens.Un code qui croit que le nom d'une personne ne peut contenir que certains caractères est stupide, offensant et erroné.
Le code qui tente de réduire Unicode en ASCII n'est pas simplement faux, son auteur ne devrait plus jamais être autorisé à travailler à nouveau en programmation. Période. Je ne suis même pas certain qu'ils devraient même être autorisés à revoir, car cela ne leur a manifestement pas fait beaucoup de bien jusqu'à présent.
Le code qui croit qu'il existe un moyen de prétendre qu'il n'existe aucun encodage de fichier texte est cassé et dangereux. Pourrait aussi bien pousser l'autre œil.
Le code qui convertit les caractères inconnus
?
est cassé, stupide, braindead et va à l'encontre de la recommandation standard, qui dit de NE PAS FAIRE CELA! RTFM pour pourquoi pas.Le code qui croit pouvoir deviner de manière fiable l'encodage d'un fichier texte non marqué est coupable d'un mélange fatal d'orgueil et de naïveté que seul un éclair de Zeus corrigera.
Le code qui croit que vous pouvez utiliser les
printf
largeurs 🐪 pour remplir et justifier les données Unicode est cassé et incorrect.Le code qui croit qu'une fois que vous avez réussi à créer un fichier par un nom donné, que lorsque vous exécutez
ls
oureaddir
sur son répertoire englobant, vous trouverez réellement que le fichier avec le nom sous lequel vous l'avez créé est bogué, cassé et incorrect. Arrêtez d'être surpris par ça!Le code qui croit que l'UTF-16 est un encodage à largeur fixe est stupide, cassé et faux. Révoquer leur licence de programmation.
Le code qui traite les points de code d'un avion un peu différemment de ceux de n'importe quel autre avion est ipso facto cassé et faux. Retourne à l'école.
Code qui croit que des choses comme
/s/i
ne peuvent que correspondre"S"
ou"s"
sont cassées et erronées. Tu serais surpris.Le code utilisé
\PM\pM*
pour rechercher des grappes de graphèmes au lieu d'utiliser\X
est cassé et incorrect.Les personnes qui souhaitent retourner dans le monde ASCII devraient être chaleureusement encouragées à le faire, et en l'honneur de leur glorieuse mise à niveau, elles devraient recevoir gratuitement une machine à écrire manuelle pré-électrique pour tous leurs besoins de saisie de données. Les messages qui leur sont envoyés doivent être envoyés via un télégraphe à 40 caractères par ligne et remis en mains propres par un service de messagerie. ARRÊTEZ.
😱 𝕾 𝖀 𝕸 𝕸 𝕬 𝕽 𝖄 😱
Je ne sais pas combien plus "Unicode par défaut dans 🐪" vous pouvez obtenir que ce que j'ai écrit. Eh bien, oui je le fais: vous devriez utiliser
Unicode::Collate
etUnicode::LineBreak
aussi. Et probablement plus.Comme vous le voyez, il y a beaucoup trop de choses Unicode que vous avez vraiment n'avoir à se soucier pour qu'il y ait jamais existe une telle chose comme « défaut Unicode ».
Ce que vous allez découvrir, tout comme nous l'avons fait en 🐪 5.8, qu'il est tout simplement impossible d'imposer toutes ces choses à du code qui n'a pas été conçu dès le début pour en tenir compte. Votre égoïsme bien intentionné vient de briser le monde entier.
Et même une fois que vous l'avez fait, il y a encore des problèmes critiques qui nécessitent beaucoup de réflexion pour être correct. Il n'y a aucun interrupteur que vous pouvez actionner. Rien que du cerveau, et je veux dire du vrai cerveau , suffira ici. Il y a beaucoup de choses à apprendre. Modulo la retraite à la machine à écrire manuelle, vous ne pouvez tout simplement pas espérer passer par ignorance. Nous sommes au 21ˢᵗ siècle, et vous ne pouvez pas désirer Unicode par ignorance volontaire.
Vous devez l'apprendre. Période. Il ne sera jamais aussi facile que «tout fonctionne,» car cela garantira que beaucoup de choses ne fonctionnent - ce qui invalide l'hypothèse qu'il peut jamais y avoir un moyen de «faire fonctionner tout cela».
Vous pourrez peut-être obtenir quelques valeurs par défaut raisonnables pour un nombre très limité et très limité d'opérations, mais non sans penser aux choses beaucoup plus que je ne le pense.
À titre d'exemple, l'ordre canonique va provoquer de vrais maux de tête. 😭
"\x{F5}"
'õ' ,"o\x{303}"
'õ' ,"o\x{303}\x{304}"
'ȭ' et"o\x{304}\x{303}"
'ō̃' devraient tous correspondre à 'õ' , mais comment allez-vous faire cela dans le monde? C'est plus difficile qu'il n'y paraît, mais c'est quelque chose dont vous devez tenir compte. 💣S'il y a une chose que je sais sur Perl, c'est ce que ses bits Unicode font et ne font pas, et cette chose que je vous promets: "̲ᴛ̲ʜ̲ᴇ̲ʀ̲ᴇ̲ ̲ɪ̲s̲ ̲ɴ̲ᴏ̲ ̲U̲ɴ̲ɪ̲ᴄ̲ᴏ̲ᴅ̲ᴇ̲ ̲ᴍ̲ᴀ̲ɢ̲ɪ̲ᴄ̲ ̲ʙ̲ᴜ̲ʟ̲ʟ̲ᴇ̲ᴛ̲ ̲" 😞
Vous ne pouvez pas simplement modifier certains paramètres par défaut et obtenir une navigation en douceur. Il est vrai que je lance 🐪 avec
PERL_UNICODE
set to"SA"
, mais c'est tout, et même c'est surtout pour les choses en ligne de commande. Pour un vrai travail, je passe par toutes les étapes décrites ci-dessus, et je le fais très, ** très ** avec soin.😈 ¡ƨdləɥ ƨᴉɥʇ ədoɥ puɐ ʻλɐp əɔᴉu ɐ əʌɐɥ ʻʞɔnl poo⅁ 😈
la source
Le traitement du texte Unicode se déroule en deux étapes. Le premier est "comment puis-je le saisir et le sortir sans perdre d'informations". La seconde est "comment traiter le texte selon les conventions linguistiques locales".
Le message de tchrist couvre les deux, mais la deuxième partie est d'où proviennent 99% du texte de son message. La plupart des programmes ne gèrent même pas les E / S correctement, il est donc important de comprendre cela avant même de commencer à vous soucier de la normalisation et du classement.
Ce message vise à résoudre ce premier problème
Lorsque vous lisez des données dans Perl, peu importe leur encodage. Il alloue de la mémoire et y stocke les octets. Si vous dites
print $str
, il transfère simplement ces octets à votre terminal, qui est probablement configuré pour supposer que tout ce qui y est écrit est UTF-8, et votre texte apparaît.Merveilleux.
Sauf que non. Si vous essayez de traiter les données comme du texte, vous verrez que quelque chose de mauvais se produit. Vous n'avez pas besoin d'aller plus loin que
length
de voir que ce que Perl pense de votre chaîne et ce que vous pensez de votre chaîne ne sont pas d'accord. Écrivez une ligne comme:perl -E 'while(<>){ chomp; say length }'
et tapez文字化け
et vous obtenez 12 ... pas la bonne réponse, 4.C'est parce que Perl suppose que votre chaîne n'est pas du texte. Vous devez lui dire que c'est du texte avant qu'il ne vous donne la bonne réponse.
C'est assez simple; le module Encode a les fonctions pour le faire. Le point d'entrée générique est
Encode::decode
(ouuse Encode qw(decode)
bien sûr). Cette fonction prend une chaîne du monde extérieur (ce que nous appellerons "octets", une façon de dire "octets 8 bits"), et la transforme en un texte que Perl comprendra. Le premier argument est un nom de codage de caractères, comme "UTF-8" ou "ASCII" ou "EUC-JP". Le deuxième argument est la chaîne. La valeur de retour est le scalaire Perl contenant le texte.(Il y a aussi
Encode::decode_utf8
, qui suppose UTF-8 pour l'encodage.)Si nous réécrivons notre one-liner:
Nous tapons 文字 化 け et obtenons "4" comme résultat. Succès.
C'est là, la solution à 99% des problèmes Unicode en Perl.
La clé est, chaque fois qu'un texte entre dans votre programme, vous devez le décoder. Internet ne peut pas transmettre de caractères. Les fichiers ne peuvent pas stocker de caractères. Il n'y a aucun personnage dans votre base de données. Il n'y a que des octets et vous ne pouvez pas traiter les octets comme des caractères en Perl. Vous devez décoder les octets encodés en caractères Perl avec le module Encode.
L'autre moitié du problème consiste à extraire des données de votre programme. C'est facile à; vous dites simplement
use Encode qw(encode)
, décidez de l'encodage de vos données (UTF-8 pour les terminaux qui comprennent UTF-8, UTF-16 pour les fichiers sous Windows, etc.), puisencode($encoding, $data)
sortez le résultat au lieu de simplement le sortir$data
.Cette opération convertit les caractères de Perl, sur lesquels votre programme fonctionne, en octets pouvant être utilisés par le monde extérieur. Ce serait beaucoup plus facile si nous pouvions simplement envoyer des caractères sur Internet ou à nos terminaux, mais nous ne pouvons pas: octets uniquement. Nous devons donc convertir les caractères en octets, sinon les résultats ne sont pas définis.
Pour résumer: encoder toutes les sorties et décoder toutes les entrées.
Nous allons maintenant parler de trois problèmes qui rendent cela un peu difficile. Le premier est les bibliothèques. Gèrent-ils correctement le texte? La réponse est ... ils essaient. Si vous téléchargez une page Web, LWP vous rendra votre résultat sous forme de texte. Si vous appelez la bonne méthode sur le résultat, c'est-à-dire (et il se trouve que
decoded_content
noncontent
, qui n'est que le flux d'octets qu'il a obtenu du serveur.) Les pilotes de base de données peuvent être floconneux; si vous utilisez DBD :: SQLite avec seulement Perl, cela fonctionnera, mais si un autre outil a mis du texte stocké sous forme d'encodage autre que UTF-8 dans votre base de données ... eh bien ... ça ne sera pas géré correctement jusqu'à ce que vous écriviez du code pour le gérer correctement.La sortie des données est généralement plus facile, mais si vous voyez "caractère large en caractères d'imprimerie", alors vous savez que vous gâchez l'encodage quelque part. Cet avertissement signifie "hé, vous essayez de divulguer des caractères Perl au monde extérieur et cela n'a aucun sens". Votre programme semble fonctionner (car l'autre extrémité gère généralement correctement les caractères Perl bruts), mais il est très endommagé et peut cesser de fonctionner à tout moment. Fixez-le avec un explicite
Encode::encode
!Le deuxième problème est le code source codé UTF-8. Sauf si vous le dites
use utf8
en haut de chaque fichier, Perl ne supposera pas que votre code source est UTF-8. Cela signifie que chaque fois que vous dites quelque chose commemy $var = 'ほげ'
, vous injectez des déchets dans votre programme qui vont tout casser horriblement. Vous n'avez pas à "utiliser utf8", mais si vous ne le faites pas, vous ne devez pas utiliser de caractères non ASCII dans votre programme.Le troisième problème est de savoir comment Perl gère le passé. Il y a longtemps, Unicode n'existait pas et Perl supposait que tout était du texte latin-1 ou binaire. Ainsi, lorsque des données arrivent dans votre programme et que vous commencez à les traiter comme du texte, Perl traite chaque octet comme un caractère Latin-1. C'est pourquoi, lorsque nous avons demandé la longueur de "文字 化 け", nous en avons obtenu 12. Perl a supposé que nous fonctionnions sur la chaîne latine-1 "æååã" (qui est de 12 caractères, dont certains ne sont pas imprimés).
C'est ce qu'on appelle une «mise à niveau implicite», et c'est une chose parfaitement raisonnable à faire, mais ce n'est pas ce que vous voulez si votre texte n'est pas Latin-1. C'est pourquoi il est essentiel de décoder explicitement l'entrée: si vous ne le faites pas, Perl le fera, et il pourrait le faire mal.
Les gens rencontrent des problèmes lorsque la moitié de leurs données est une chaîne de caractères appropriée et que certaines sont encore binaires. Perl interprétera la partie qui est encore binaire comme s'il s'agissait de texte Latin-1, puis la combinera avec les données de caractères correctes. Cela donnera l'impression que la gestion correcte de vos personnages a interrompu votre programme, mais en réalité, vous ne l'avez pas suffisamment corrigé.
Voici un exemple: vous avez un programme qui lit un fichier texte encodé en UTF-8, vous clouez un Unicode
PILE OF POO
sur chaque ligne et vous l'imprimez. Vous l'écrivez comme:Et puis exécutez sur certaines données encodées UTF-8, comme:
Il imprime les données UTF-8 avec un caca à la fin de chaque ligne. Parfait, mon programme fonctionne!
Mais non, vous faites juste une concaténation binaire. Vous lisez des octets du fichier, supprimez un
\n
avec chomp, puis clouez sur les octets dans la représentation UTF-8 duPILE OF POO
personnage. Lorsque vous révisez votre programme pour décoder les données du fichier et encoder la sortie, vous remarquerez que vous obtenez des ordures ("ð ©") au lieu du caca. Cela vous amènera à croire que le décodage du fichier d'entrée n'est pas la bonne chose à faire. Ce n'est pas.Le problème est que le caca est implicitement mis à niveau en latin-1. Si vous
use utf8
faites le texte littéral au lieu de binaire, alors cela fonctionnera à nouveau!(C'est le problème numéro un que je vois en aidant les gens avec Unicode. Ils se sont bien débrouillés et cela a cassé leur programme. C'est ce qui est triste avec des résultats indéfinis: vous pouvez avoir un programme de travail pendant longtemps, mais quand vous commencez à le réparer, ne vous inquiétez pas; si vous ajoutez des instructions d'encodage / décodage à votre programme et qu'il se casse, cela signifie simplement que vous avez plus de travail à faire. La prochaine fois, lorsque vous concevrez avec Unicode à l'esprit depuis le début, ce sera beaucoup plus facile!)
C'est vraiment tout ce que vous devez savoir sur Perl et Unicode. Si vous dites à Perl quelles sont vos données, elles ont le meilleur support Unicode parmi tous les langages de programmation populaires. Si vous supposez qu'il saura comme par magie quel type de texte vous l'alimentez, alors vous allez détruire vos données de manière irrévocable. Ce n'est pas parce que votre programme fonctionne aujourd'hui sur votre terminal UTF-8 qu'il fonctionnera demain sur un fichier encodé UTF-16. Alors sécurisez-le maintenant et évitez le casse-tête de mettre à la poubelle les données de vos utilisateurs!
La partie facile de la gestion d'Unicode est l'encodage de la sortie et le décodage de l'entrée. La partie difficile consiste à trouver toutes vos entrées et sorties, et à déterminer de quel encodage il s'agit. Mais c'est pourquoi vous obtenez le gros lot :)
la source
Encode
module est fastidieuse et sujette aux erreurs, et cela rend la lecture du code concernant les E / S vraiment pénible. Les couches d'E / S offrent une solution car elles encodent et décodent de manière transparente, le cas échéant.open
etbinmode
permettre leur spécification, et pragmaopen
définit les valeurs par défaut, comme le recommande tchrist dans sa réponse.Nous sommes tous d'accord pour dire que c'est un problème difficile pour de nombreuses raisons, mais c'est précisément la raison pour essayer de le rendre plus facile pour tout le monde.
Il existe un module récent sur CPAN, utf8 :: all , qui tente de "mettre en marche Unicode. Tout cela".
Comme cela a été souligné, vous ne pouvez pas par magie faire en sorte que l'ensemble du système (programmes externes, requêtes Web externes, etc.) utilise également Unicode, mais nous pouvons travailler ensemble pour créer des outils sensés qui facilitent la résolution des problèmes courants. C'est la raison pour laquelle nous sommes programmeurs.
Si utf8 :: all ne fait pas quelque chose que vous pensez qu'il devrait, améliorons-le pour l'améliorer. Ou créons des outils supplémentaires qui, ensemble, peuvent répondre au mieux aux besoins variés des gens.
"
la source
utf8::all
module cité . Il a été écrit avant launicode_strings
fonctionnalité, que Fɪɴᴀʟʟʏ ᴀɴᴅ ᴀᴛ Lᴏɴɢ Lᴀsᴛ corrige pour les regexes/u
. Je ne suis pas convaincu que cela soulève une exception sur les erreurs de codage, et c'est quelque chose que vous devez vraiment avoir. Il ne se charge pas dans leuse charnames ":full"
pragma, qui n'est pas encore chargé automatiquement. Il ne met pas en garde contre[a-z]
et telles,printf
les largeurs de chaîne, en utilisant\n
au lieu de\R
et.
au lieu de\X
, mais c'est peut-être plus unePerl::Critic
question. Si c'était moi, j'ajouterais 𝐍𝐅𝐃 et 𝐍𝐅𝐂 dehors.unichars -gs '/(?=\P{Ll})\p{Lower}|(?=\P{Lu})\p{Upper}/x' | ucsort --upper | cat -n | less -r
. De même, les petites étapes de prétraitement comme... | ucsort --upper --preprocess='s/(\d+)/sprintf "%#012d", $1/ge'
peuvent être très bien aussi, et je ne voudrais pas prendre les décisions des autres à leur place. Je construis toujours ma boîte à outils Unicode .Je pense que vous comprenez mal Unicode et sa relation avec Perl. Peu importe la façon dont vous stockez les données, Unicode, ISO-8859-1 , ou bien d'autres choses, votre programme doit savoir comment interpréter les octets qu'il reçoit en entrée (décodage) et comment représenter les informations qu'il souhaite produire (codage ). Obtenez cette interprétation erronée et vous brouillez les données. Il n'y a pas de configuration par défaut magique à l'intérieur de votre programme qui va dire aux choses en dehors de votre programme comment agir.
Vous pensez que c'est difficile, très probablement, parce que vous êtes habitué à tout ce qui est ASCII. Tout ce à quoi vous auriez dû penser a été tout simplement ignoré par le langage de programmation et toutes les choses avec lesquelles il devait interagir. Si tout n'utilisait que de l'UTF-8 et que vous n'aviez pas le choix, alors l'UTF-8 serait tout aussi simple. Mais tout n'utilise pas UTF-8. Par exemple, vous ne voulez pas que votre handle d'entrée pense qu'il obtient des octets UTF-8 à moins qu'il ne le soit réellement, et vous ne voulez pas que vos poignées de sortie soient UTF-8 si la chose qui les lit peut gérer UTF-8 . Perl n'a aucun moyen de savoir ces choses. Voilà pourquoi vous êtes le programmeur.
Je ne pense pas qu'Unicode dans Perl 5 soit trop compliqué. Je pense que c'est effrayant et les gens l'évitent. Il y a une différence. À cette fin, j'ai mis Unicode dans Learning Perl, 6th Edition , et il y a beaucoup de choses Unicode dans la programmation Perl efficace . Vous devez passer du temps pour apprendre et comprendre Unicode et son fonctionnement. Sinon, vous ne pourrez pas l'utiliser efficacement.
la source
use utf8_everywhere
rend les gens heureux. Pourquoi pas le dernier?En lisant ce fil, j'ai souvent l'impression que les gens utilisent " UTF-8 " comme synonyme de " Unicode ". Veuillez faire une distinction entre les "points de code" d'Unicode qui sont un parent élargi du code ASCII et les différents "encodages" d'Unicode. Et il y en a quelques-uns, dont UTF-8, UTF-16 et UTF-32 sont les actuels et quelques autres sont obsolètes.
S'il vous plaît, UTF-8 (ainsi que tous les autres encodages ) existe et n'a de sens qu'en entrée ou en sortie uniquement. En interne, depuis Perl 5.8.1, toutes les chaînes sont conservées en tant que «points de code» Unicode. Certes, vous devez activer certaines fonctionnalités comme précédemment admirablement couvertes.
la source
Il y a une quantité vraiment horrible de code ancien dans la nature, en grande partie sous la forme de modules CPAN communs. J'ai constaté que je dois être assez prudent en activant Unicode si j'utilise des modules externes qui pourraient être affectés par celui-ci, et j'essaie toujours d'identifier et de corriger certaines défaillances liées à Unicode dans plusieurs scripts Perl que j'utilise régulièrement (en particulier, iTiVo échoue mal sur tout ce qui n'est pas ASCII 7 bits en raison de problèmes de transcodage).
la source
-C
option pour m'assurer que Perl est sur la même page que je suis en Unicode, car je continue de le faire décider d'utiliser ISO 8859/1 au lieu d'Unicode même si je le configure explicitement$LANG
et$LC_ALL
correctement. (Cela peut en fait refléter des bogues dans les bibliothèques de paramètres régionaux de la plate-forme.) Quoi qu'il en soit, il est très ennuyeux de ne pas pouvoir utiliser iTivo sur des programmes avec des accents, car les scripts Perl qui font le travail tombent avec des erreurs de conversion.-C
sans options est bogué et sujet aux erreurs . Vous brisez le monde. Réglez l'PERL5OPT
envariable sur-C
et vous verrez ce que je veux dire. Nous avons essayé de cette façon dans la version 5.8, et ce fut un désastre. Vous ne pouvez tout simplement pas et ne devez pas dire aux programmes qui ne s'y attendent pas qu'ils traitent maintenant avec Unicode, qu'ils le veuillent ou non. Il y a aussi des problèmes de sécurité. À tout le moins, tout ce quiprint while <>
se cassera si des données binaires sont transmises. Il en sera de même pour tout le code de la base de données. C'est une terrible idée.-C
sans options. L'invocation spécifique avec laquelle je travaillais était-CSDA
. Cela dit, j'ai été bloqué avec 5.8.x pendant longtemps (bonjour MacPorts ...), alors peut-être que cela en faisait partie.Vous devez activer la fonction de chaînes unicode, et c'est la valeur par défaut si vous utilisez la v5.14;
Vous ne devriez pas vraiment utiliser les identifiants unicode esp. pour le code étranger via utf8 car ils ne sont pas sécurisés en perl5, seul cperl a obtenu ce droit. Voir par exemple http://perl11.org/blog/unicode-identifiers.html
Concernant utf8 pour vos descripteurs de fichiers / flux: vous devez décider vous-même de l'encodage de vos données externes. Une bibliothèque ne peut pas le savoir, et comme même libc ne prend pas en charge utf8, les données utf8 appropriées sont rares. Il y a plus de wtf8, l'aberration des fenêtres d'utf8.
BTW: Moose n'est pas vraiment "Modern Perl", ils ont juste détourné le nom. Moose est parfait Perl postmoderne de style Larry Wall mélangé à tout le style Bjarne Stroustrup, avec une aberration éclectique de la syntaxe perl6 appropriée, par exemple en utilisant des chaînes pour les noms de variable, une syntaxe de champs horrible et une implémentation naïve très immature qui est 10x plus lente qu'une bonne mise en œuvre. cperl et perl6 sont les véritables perls modernes, où la forme suit la fonction, et l'implémentation est réduite et optimisée.
la source