J'ai des résultats intéressants en essayant de discerner les différences entre l'utilisation de Encode::decode("utf8", $var)
et utf8::decode($var)
. J'ai déjà découvert qu'appeler l'ancien plusieurs fois sur une variable finira par entraîner une erreur "Impossible de décoder la chaîne avec des caractères larges à ..." alors que la dernière méthode fonctionnera heureusement autant de fois que vous le souhaitez, renvoyant simplement faux. Ce que j'ai de la difficulté à comprendre, c'est comment la fonction length
renvoie des résultats différents selon la méthode que vous utilisez pour décoder. Le problème se pose parce que j'ai affaire à du texte utf8 "doublement encodé" provenant d'un fichier extérieur. Pour illustrer ce problème, j'ai créé un fichier texte "test.txt" avec les caractères Unicode suivants sur une ligne: U + 00e8, U + 00ab, U + 0086, U + 000a. Ces caractères Unicode sont le double-encodage du caractère Unicode U + 8acb, avec un caractère de nouvelle ligne. Le fichier a été codé sur disque en UTF8. Je lance le script Perl suivant:Perl: utf8 :: decode contre Encode :: decode
#!/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:\[email protected]\n";
my @hex = (unpack('H*', $test));
print "Hex:\[email protected]\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:\[email protected]\n";
@hex = (unpack('H*', $test));
print "Hex:\[email protected]\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:\[email protected]\n";
@hex = (unpack('H*', $test));
print "Hex:\[email protected]\n";
Cela donne le résultat suivant:
Length: 7 utf8 flag: Unicode: 195 168 194 171 194 139 10 Hex: c3a8c2abc28b0a ============== Length: 4 utf8 flag: 1 Unicode: 232 171 139 10 Hex: c3a8c2abc28b0a ============== Length: 2 utf8 flag: 1 Unicode: 35531 10 Hex: e8ab8b0a
C'est ce que j'attendais. La longueur est à l'origine 7 parce que perl pense que $ test est juste une série d'octets. Après le décodage une fois, perl sait que $ test est une série de caractères encodés en utf8 (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 encore 7 octets en mémoire). Après le deuxième décodage, $ test contient 4 octets interprétés comme 2 caractères, ce que j'attendrais puisque Encode :: decode prend les 4 points de code et les interprète comme des octets encodés en utf8, ce qui donne 2 caractères. La chose étrange est quand je modifie le code pour appeler utf8 :: decode à la place (remplacer tous $ test = Encode :: decode ("utf8", $ test), avec utf8 :: decode ($ test))
donne une sortie presque identique, seul le résultat d'une longueur différente:
Length: 7 utf8 flag: Unicode: 195 168 194 171 194 139 10 Hex: c3a8c2abc28b0a ============== Length: 4 utf8 flag: 1 Unicode: 232 171 139 10 Hex: c3a8c2abc28b0a ============== Length: 4 utf8 flag: 1 Unicode: 35531 10 Hex: e8ab8b0a
Il semble que perl premier compte les octets avant le décodage (comme prévu), puis compte les caractères après le premier décodage, mais compte les octets à nouveau après le deuxième décodage (pas prévu). Pourquoi ce changement aurait-il lieu? Y a-t-il une défaillance dans ma compréhension du fonctionnement de ces fonctions de décodage?
Merci,
Matt
Pourquoi avez-vous besoin de modules au lieu de les utiliser? –
Je n'ai pas
use
utf8 car cela indique à perl que votre code est lui-même encodé en utf8, ce dont je n'ai pas besoin (http://perldoc.perl.org/utf8.html). Je suppose que j'aurais pu encoder, mais je ne suis pas arrivé. – Matt