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

Aucune raison pourquoi vous êtes 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