Perl: utf8::decode vs Encode::décoder
Je vais avoir quelques résultats intéressants en essayant de discerner les différences entre l'utilisation Encode::decode("utf8", $var)
et utf8::decode($var)
. J'ai déjà découvert que l'appel de l'ancien plusieurs fois sur une variable finira par causer une erreur "Impossible de décoder la chaîne de caractères larges à...", alors que la méthode de ce dernier seront heureux de vous exécuter autant de fois que vous le souhaitez, il suffit de retourner false.
Ce que je vais avoir de la difficulté à comprendre comment le length
fonction renvoie des résultats différents en fonction de la méthode que vous utilisez pour décoder. Le problème se pose parce que je fais affaire avec "doublement codé" utf8 texte à partir d'un en dehors de fichier. Pour illustrer cette question, j'ai créé un fichier texte "test.txt" avec les caractères Unicode suivants sur une seule ligne: U+00e8, U+00ab, U+0086, U+000a. Ces caractères Unicode sont le double codage de caractères Unicode U+8acb, avec un caractère de saut de ligne. Le fichier a été encodée à disque en UTF8. Je puis exécutez le script perl suivant:
#!/usr/bin/perl
use strict;
use warnings;
require "Encode.pm";
require "utf8.pm";
open FILE, "test.txt" or die $!;
my @lines = <FILE>;
my $test = $lines[0];
print "Length: " . (length $test) . "\n";
print "utf8 flag: " . utf8::is_utf8($test) . "\n";
my @unicode = (unpack('U*', $test));
print "Unicode:\n@unicode\n";
my @hex = (unpack('H*', $test));
print "Hex:\n@hex\n";
print "==============\n";
$test = Encode::decode("utf8", $test);
print "Length: " . (length $test) . "\n";
print "utf8 flag: " . utf8::is_utf8($test) . "\n";
@unicode = (unpack('U*', $test));
print "Unicode:\n@unicode\n";
@hex = (unpack('H*', $test));
print "Hex:\n@hex\n";
print "==============\n";
$test = Encode::decode("utf8", $test);
print "Length: " . (length $test) . "\n";
print "utf8 flag: " . utf8::is_utf8($test) . "\n";
@unicode = (unpack('U*', $test));
print "Unicode:\n@unicode\n";
@hex = (unpack('H*', $test));
print "Hex:\n@hex\n";
Cela donne le résultat suivant:
Longueur: 7 utf8 drapeau: Unicode: 195 168 194 171 194 139 10 Hex: c3a8c2abc28b0a ============== Longueur: 4 utf8 drapeau: 1 Unicode: 232 171 139 10 Hex: c3a8c2abc28b0a ============== Longueur: 2 utf8 drapeau: 1 Unicode: 35531 10 Hex: e8ab8b0a
C'est ce à quoi je m'attends. La longueur est à l'origine 7, car perl pense que $test est juste une série d'octets. Après décodage, une fois, perl sait que $test est une série de caractères utf8-codé (c'est à dire au lieu de retourner une longueur de 7 octets, perl renvoie une longueur de 4 caractères, même si $test est toujours de 7 octets en mémoire). Après la deuxième décodage, $test contient 4 octets interprétée comme 2 personnages, ce qui est ce que je m'attends depuis Encode::decode a pris les 4 points de code et les a interprétées comme utf8-octets codés, résultant en 2 caractères. La chose étrange est que lorsque j'ai modifier le code pour appeler utf8::décoder la place (remplacer tous les $test = Encode::decode("utf8", $test); avec l'utf8::decode($test))
Cela donne presque identique de sortie, seulement la conséquence de la longueur diffère:
Longueur: 7 utf8 drapeau: Unicode: 195 168 194 171 194 139 10 Hex: c3a8c2abc28b0a ============== Longueur: 4 utf8 drapeau: 1 Unicode: 232 171 139 10 Hex: c3a8c2abc28b0a ============== Longueur: 4 utf8 drapeau: 1 Unicode: 35531 10 Hex: e8ab8b0a
Il semble que perl premier compte les octets avant de décodage (comme prévu), puis compte le nombre de caractères après le premier décodage, mais alors en compte les octets après la deuxième décodage (ne devrait pas). Pourquoi serait-ce basculement? Est-il une parenthèse dans ma compréhension de la façon dont ces fonctions de décodage de travail?
Merci,
Matt
require
ing modules au lieu de use
ing?Je n'ai pas <code>utiliser</code> utf-8, car cela indique à perl que votre code est lui-même utf8 codé, je n'ai pas besoin (perldoc.perl.org/utf8.html). Je suppose que j'aurais pu le <code>utiliser</code>d Coder, mais je viens de passer pas à.
OriginalL'auteur Matt | 2010-12-02
Vous devez vous connecter pour publier un commentaire.
Vous n'êtes pas censé utiliser les fonctions de la
utf8
pragma module. Sa documentation dit:Toujours utiliser le module de Coder, et aussi voir la question Liste de contrôle pour aller de l'Unicode façon avec Perl.
unpack
est trop faible, il ne fait même pas vous donner de vérification des erreurs.Vous allez mal avec l'hypothèse que les octects
E8 AB 86 0A
sont le résultat de l'UTF-8 double-codage les personnages諆
etnewline
. C'est la représentation d'un seul l'encodage UTF-8 de ces caractères. Peut-être l'ensemble de la confusion de votre côté découle de cette erreur.length
est unappropriately surchargé, à certains moments, il détermine la longueur en caractères, ou la longueur (en octets). Mieux utiliser les outils tels queDevel::Peek
.Il dit "Ne pas utiliser ce pragma pour autre chose que de dire à Perl que votre script est écrit en UTF-8. L'utilité des fonctions décrites ci-dessous sont utilisables directement sans utiliser utf8;.", qui, clairement, ne signifie pas "vous n'êtes pas censé utiliser les fonctions de l'utf8 pragma module". Cela signifie que vous n'avez pas besoin d'utiliser le pragma pour importer les fonctions.
OriginalL'auteur daxim
S'avère que c'était un bug: https://rt.perl.org/rt3//Public/Bug/Display.html?id=80190.
OriginalL'auteur Matt