596 votes

Pourquoi Perl moderne évite-t-il l'UTF-8 par défaut ?

Je me demande pourquoi la plupart des solutions modernes construites en Perl n'e U 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 des choses. [ ] s siècle, les nouveaux projets d'envergure (ou les projets ayant une perspective importante) devraient faire en sorte que leur logiciel soit compatible avec l'UTF-8 à partir de zéro. Pourtant, je ne vois pas comment cela pourrait se produire. [ ] M permet des mesures strictes et des avertissements U . M réduit également le modèle de base, mais pas l'UTF-8

Pourquoi ? Existe-t-il des raisons d'éviter l'UTF-8 dans moder ?


Le commentaire de @tchrist est devenu trop long, alors je l'ajoute

Il semble que je n'ai pas été assez clair. L

t et moi voyons la situation de manière 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 (les utilisateurs de Perl et les codeurs) avons besoin d'une couche (ou d'un pragma) qui

t Les aspects à couvrir sont trop nombreux pour que je puisse les lire et y réfléchir pendant des jours, voire des semaines. S t tente de prouver qu'il n'existe pas une seule façon "d'activer UTF-8". Je n'ai pas beaucoup de connaissances en la matière. [ ]

J'ai joué autour de R et UTF-8 était ju comme j'en avais besoin . Je n'ai pas eu de problème, cela a fonctionné. Peut-être qu'il y a des limitations plus profondes, mais au début, tout ce que j'ai fait, c'est d'essayer d'obtenir des résultats.

Cela ne devrait-il pas être un objectif pour Perl 5 moderne ? J'insiste davantage : Je ne suggère pas que l'UTF-8 soit le jeu de caractères par défaut pour le noyau de Perl. en un clin d'œil pour ceux qui d n p

Autre exemple, mais avec un ton plus négatif. Les frameworks devraient faciliter le développement. Il y a quelques années, j'ai essayé des frameworks web, mais je les ai jetés parce que "activer UTF-8" était si obscur. Je n'ai pas trouvé comment et où accrocher le support Unicode. Cela m'a pris tellement de temps que j'ai trouvé plus facile d'utiliser l'ancienne méthode. Maintenant, j'ai vu qu'il y avait une prime à faire M 2 Comment rendre Mason2 UTF-8 . Il s'agit donc d'un cadre assez récent, mais son utilisation avec l'UTF-8 nécessite une connaissance approfondie de son fonctionnement interne. [ ]

J'aime beaucoup Perl. Mais la gestion de l'Unicode est pénible. Je me retrouve toujours t est juste et répond à mes questions : les nouveaux projets n'attirent pas UTF-8 parce qu'il i

4 votes

Bonjour à tous - Ces commentaires soulèvent quelques questions. Ce que j'ai fait, c'est prendre un instantané des commentaires ici et les déposer dans ce salon de discussion pour qu'ils puissent être lus. chat.stackover

16 votes

Je suis désolé mais je suis d'accord avec @tchrist -- UTF-8 est extrêmement difficile. Il n'existe pas de cadre ou d'outil qui permette d'actionner un interrupteur et de le gérer correctement. C'est quelque chose auquel vous devez penser directement lors de la conception de votre application - et non quelque chose qu'un framework ou un langage peut gérer pour vous. Si rakudo a fonctionné pour vous, c'est que vous n'avez pas été assez aventureux avec vos cas de test -- car il prendra plusieurs des exemples de cas de test.

12 votes

Qu'attendez-vous exactement de Moose ou de Modern::Perl ? Créer magiquement des données de caractères codées de manière aléatoire dans les fichiers et les bases de données.

1199voto

tchrist Points 47116

64 votes

Comme l'a souligné Sherm Pendley : "Tous !". Si j'écris t e de faire avancer les choses. Ce n'est pas le cas. Votre modèle de référence le prouve. Tout le monde n'a pas les connaissances nécessaires pour mettre autant de gobelets dans la bonne position. Je suis désolé, j'ai eu une longue et difficile journée, je vais donc commenter en m

13 votes

@wk : [ ] perl -i.bak -pe 's/foo/bar' des pauses ? Il y en a beaucoup dans le monde. W eq ? A lc le transformer en UCA1 ? Comment pouvez-vous le savoir ? Comment ferez-vous correspondre des glyphes partiels et/ou discontigus ? Est-il normal que tous les anciens codes contenant des données de 8 bits ne puissent plus être compilés ? Est-il normal que Perl ne fonctionne plus avec des données binaires ? Est-ce que c'est normal d'avoir des [ ] a-z sans leur consentement ? Est-il acceptable de briser les graphèmes ? Un ralentissement de 100x du code de tri est-il [ ]

1 votes

@tchrist : pourquoi cela devrait-il casser un vieux code, whe n projets ? Oublions le code hérité et le cœur de Perl. Par exemple, y a-t-il une raison d'éviter UTF-8 dans les projets basés sur Moose ? Si ce n'est pas le cas, je pense que Moose pourrait permettre le support de l'UTF-8 aussi largement que possible comme il permet les avertissements et les pragma stricts. Maintenant, nous perdons juste du temps, parce qu'il y a déjà beaucoup de code écrit wi

102voto

jrockway Points 23734

Le traitement du texte Unicode se fait en deux étapes. La première est "comment puis-je l'entrer et le sortir sans perdre d'informations". La seconde est "comment traiter le texte selon les conventions de la langue locale".

Le post de tchrist couvre les deux, mais la deuxième partie est celle d'où provient 99% du texte de son post. La plupart des programmes ne gèrent même pas correctement les E/S, il est donc important de comprendre cela avant même de commencer à se préoccuper de la normalisation et de la collation.

Ce billet vise à résoudre ce premier problème

Lorsque vous lisez des données dans Perl, le codage n'a pas d'importance. Il alloue de la mémoire et y stocke les octets. Si vous dites print $str il transmet simplement ces octets à votre terminal, qui est probablement configuré pour supposer que tout ce qui lui est écrit est UTF-8, et votre texte s'affiche.

Merveilleux.

Sauf que ça ne l'est pas. Si vous essayez de traiter les données comme du texte, vous verrez que quelque chose de mauvais se passe. Vous n'avez pas besoin d'aller plus loin que length pour voir que ce que Perl pense de votre chaîne et ce que vous pensez de votre chaîne sont en désaccord. Ecrivez une phrase 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 pour qu'il vous donne la bonne réponse.

C'est assez facile ; le module Encode possède les fonctions pour le faire. Le point d'entrée générique est Encode::decode (o use Encode qw(decode) bien sûr). Cette fonction prend une chaîne de caractères du monde extérieur (ce que nous appellerons des "octets", une façon fantaisiste 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 second argument est la chaîne de caractères. La valeur de retour est le scalaire Perl contenant le texte.

(Il existe également Encode::decode_utf8 qui suppose que l'encodage est UTF-8).

Si on réécrit notre phrase d'introduction :

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

On tape 文字化け et on obtient "4" comme résultat. Succès.

C'est la solution à 99 % des problèmes d'Unicode en Perl.

La clé est que, dès qu'un texte entre dans votre programme, vous devez le décoder. L'Internet ne peut pas transmettre de caractères. Les fichiers ne peuvent pas stocker de caractères. Il n'y a pas de caractères 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 codés en caractères Perl avec le module Encode.

L'autre moitié du problème consiste à faire sortir les données de votre programme. C'est facile, il suffit de dire 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. encode($encoding, $data) au lieu de simplement sortir $data .

Cette opération convertit les caractères de Perl, sur lesquels votre programme fonctionne, en octets utilisables par le monde extérieur. Ce serait beaucoup plus simple si nous pouvions simplement envoyer des caractères sur Internet ou sur nos terminaux, mais ce n'est pas possible : ce sont des octets. Nous devons donc convertir les caractères en octets, sinon les résultats sont indéfinis.

Pour résumer : coder toutes les sorties et décoder toutes les entrées.

Nous allons maintenant parler de trois problèmes qui rendent la chose un peu difficile. Le premier est celui des bibliothèques. Traitent-elles le texte correctement ? La réponse est... elles essaient. Si vous téléchargez une page web, LWP vous rendra le 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 c'est la méthode decoded_content no content qui est juste le flux d'octets qu'il a reçu du serveur). Les pilotes de base de données peuvent être instables ; si vous utilisez DBD::SQLite avec seulement Perl, cela fonctionnera, mais si un autre outil a stocké du texte dans un encodage autre que UTF-8 dans votre base de données... eh bien... il 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 "wide character in print", alors vous savez que vous vous êtes trompé dans l'encodage quelque part. Cet avertissement signifie "hé, vous essayez de faire fuir des caractères Perl vers le monde extérieur et cela n'a aucun sens". Votre programme semble fonctionner (parce que l'autre extrémité traite généralement les caractères Perl bruts correctement), mais il est très cassé et peut cesser de fonctionner à tout moment. Corrigez-le avec un Encode::encode !

Le deuxième problème est le code source codé en UTF-8. À moins que vous ne disiez 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 comme my $var = 'ほげ' vous injectez des déchets dans votre programme qui vont tout casser de manière horrible. Vous n'êtes pas obligé d'"utiliser utf8", mais si vous ne le faites pas, vous doit n'utilisez pas de caractères non ASCII dans votre programme.

Le troisième problème est la façon dont Perl gère le passé. Il y a longtemps, l'Unicode n'existait pas, et Perl partait du principe que tout était du texte en Latin-1 ou du 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 avons obtenu 12. Perl a supposé que nous opérions sur la chaîne Latin-1 "æåå" (qui compte 12 caractères, dont certains ne sont pas imprimables).

Ceci est appelé 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 en 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 correcte, et que certaines sont encore binaires. Perl interprétera la partie encore binaire comme s'il s'agissait d'un texte en Latin-1, puis la combinera avec les données de caractères correctes. Cela donnera l'impression que la gestion correcte de vos caractères a cassé 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 codé en UTF-8, vous y ajoutez un code Unicode. PILE OF POO à chaque ligne, et vous l'imprimez. Tu l'écris comme ça :

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

3 votes

Le principe est bien expliqué, mais l'approche pratique des E/S fait défaut. [ ] Encode est fastidieux et source d'erreurs, et il rend la lecture du code concernant les E/S vraiment pénible. Les couches d'E/S apportent une solution open a binmode permettent de les spécifier, et la pragmatique open définit les valeurs par défaut, comme le recommande Tchrist dans sa réponse.

51voto

Randy Stauner Points 541

Nous sommes tous d'accord pour dire qu'il s'agit d'un problème difficile pour de nombreuses raisons, mais c'est précisément la raison pour laquelle il faut essayer de le rendre plus facile pour tout le monde.

Il existe un module récent sur CPAN, utf8::tous qui tente d'"activer l'Unicode. Tout cela".

Comme cela a été souligné, il n'est pas possible de 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 judicieux qui facilitent la résolution des problèmes courants. C'est la raison pour laquelle nous sommes des programmeurs.

Si utf8::all ne fait pas quelque chose que vous pensez qu'il devrait faire, améliorons-le pour le rendre meilleur. Ou créons des outils supplémentaires qui, ensemble, peuvent répondre aux différents besoins des gens aussi bien que possible.

`

5 votes

Je vois beaucoup de une marge d'amélioration dans le document cité utf8::all module. [ ] unicode_strings La fonction F L Ls corrige les expressions rationnelles pour qu'elles aient une valeur de /u sur eux. Je ne suis pas convaincu qu'il soulève une exception sur les use charnames ":full" pragma, qui n'est pas encore [a-z] a printf largeur des chaînes de caractères, usi \n au lieu de \R a . au lieu de \X mais peut-être que ce sont des Perl::Critic matière. I

4 votes

@Schwern : s, mais n'hésitez pas à piocher dans ce que j'ai écrit ici. Pour être honnête, je suis encore en train de sentir/apprendre ce qui peut être fait. unichars -gs '/(?=\P{Ll})\p{Lower}|(?=\P{Lu})\p{Upper}/x' | ucsort --upper | cat -n | less -r . De même, les petits ... | ucsort --upper --preprocess='s/(\d+)/sprintf "%#012d", $1/ge' peuvent aussi être très gentils, et je ne voudrais pas prendre les décisions des autres à leur place. [ ] construction de mon Unicod .

13 votes

@tchrist Le gestionnaire de problèmes pour utf8 : github. Ils aimeraient connaître votre

39voto

brian d foy Points 71781

Je pense que vous comprenez mal l'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 encore, 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 veut produire (codage). Si vous vous trompez dans l'interprétation, vous déformez les données. Il n'y a pas de configuration magique par défaut à l'intérieur de votre programme qui va dire aux choses extérieures à votre programme comment agir.

Vous pensez que c'est difficile, très probablement parce que vous êtes habitué à ce que tout soit en ASCII. Tout ce à quoi vous auriez dû penser a simplement été ignoré par le langage de programmation et toutes les choses avec lesquelles il devait interagir. Si tout utilisait uniquement UTF-8 et que vous n'aviez pas le choix, alors UTF-8 serait tout aussi facile. Mais tout n'utilise pas UTF-8. Par exemple, vous ne voulez pas que votre handle d'entrée pense qu'il reçoit des octets UTF-8 à moins que ce ne soit le cas, et vous ne voulez pas que vos handles de sortie soient UTF-8 si la chose qui les lit ne peut pas gérer UTF-8. Perl n'a aucun moyen de savoir ces choses. C'est pourquoi vous êtes le programmeur.

Je ne pense pas qu'Unicode dans Perl 5 soit trop compliqué. Je pense que c'est effrayant et que les gens l'évitent. Il y a une différence. À cette fin, j'ai mis l'Unicode en Apprendre Perl, 6ème édition et il y a beaucoup d'éléments Unicode dans le fichier Programmation efficace en Perl . Vous devez prendre le temps d'apprendre et de comprendre Unicode et son fonctionnement. Sinon, vous ne serez pas en mesure de l'utiliser efficacement.

3 votes

Je pense que vous avez raison : c'est effrayant. Devrait-il l'être ? Pour moi, Unicode est une bénédiction, l'utiliser dans Perl5 ne l'est pas (je ne suppose pas que tout soit ASCII, ma langue maternelle a besoin d'au moins iso8859-4). J'ai installé Rakudo et tout ce que j'ai essayé avec UTF-8 (dans ce bac à sable limité) a fonctionné sans problème. Ai-je raté quelque chose ? Je le répète : il est bon d'avoir un support Unicode finement ajusté, mais la plupart du temps, ce n'est pas nécessaire. Pour s'éloigner du sujet, une solution est que tout le monde lise beaucoup pour comprendre le fonctionnement interne. Autre chose : nous avons sp use utf8_everywhere rend les gens heureux. [ ]

3 votes

Je persiste à penser que vous n'avez pas compris. Qu'est-ce qui a marché ? Vous n'avez pas besoin de comprendre le fonctionnement interne. Vous avez e et comment gérer les chaînes de caractères qui ont des encodages différents et des représentations différentes des mêmes caractères. Relisez les conseils de Tom. Je parie que vous trouverez la plupart de ses conseils dans Rak

0 votes

Peut-être que vous avez raison et que je n'ai pas compris, je ne veux pas polémiquer. [Mais Randy Staune est un homme qui n'est pas un homme d'affaires, mais un homme d'affaires. u . Y a-t-il un problème avec un tel module ? Ne devrions-nous pas l'avoir (ou un module similaire) dans le noyau de Perl ? De mon point de vue, cela rend l'utilisation de l'UTF-8 tellement plus facile et cohérente. [ ]

29voto

MeirG Points 161

En lisant ce fil, j'ai souvent l'impression que les gens utilisent " UTF-8 "comme synonyme de " Unicode ". Veuillez faire la distinction entre les "Code-Points" d'Unicode, qui sont une version agrandie 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 codifications ) existe et n'a de sens qu'en entrée ou en sortie. En interne, depuis Perl 5.8.1, toutes les chaînes de caractères sont conservées sous forme de "points de code" Unicode. Il est vrai que vous devez activer certaines fonctionnalités, comme cela a été admirablement décrit précédemment.

15 votes

@tchrist : la première étape consiste à faire entrer les données dans votre programme et à les diffuser dans le monde extérieur sans les détruire. ensuite, vous pourrez vous préoccuper de la co

7 votes

Je suis d'accord, faire en sorte que perl ne mette pas à la poubelle l'entrée ou la sortie doit être la première priorité. Ce que j'aimerais, c'est avoir un module ou un pragma qui pourrait incarner la conversation fictive suivante : "- Cher Perl. Pour ce programme, toutes les entrées et sorties seront exclusivement en UTF-8. Pourrais-tu, s'il te plaît, ne pas mettre mes données à la poubelle ? - Alors seulement UFT-8, dites-vous. Êtes-vous sûr ? - Oui. - Vraiment, vraiment sûr ? - Absolument. - Et vous acceptez que je puisse me comporter bizarrement si on me sert du non-UT [ ]

20 votes

Je suis d'accord pour dire que les gens confondent trop souvent U et UTF-. Il s'agit d'une approche fondamentalement et critique. n que U n'est qu'un jeu de caractères élargi Tout au plus, cela rien de plus que . U comprend muc : collation, conversion en majuscules, formes de normalisation, groupes de graphèmes, coupure de mots et de lignes, scripts, équivalents numériques, largeurs, bidirectionnalité, variantes de glyphes, comportement contextuel, locales, regexes, peigne, etc.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X