Я получаю некоторые интересные результаты, пытаясь различить различия между Encode::decode("utf8", $var)
и utf8::decode($var)
. Я уже обнаружил, что многократный вызов первого для переменной в конечном итоге приведет к ошибке «Невозможно декодировать строку с широкими символами в ...», тогда как последний метод будет успешно запускаться столько раз, сколько вы захотите, просто возвращая false.
Мне трудно понять, как функция length
возвращает разные результаты в зависимости от того, какой метод вы используете для декодирования. Проблема возникает из-за того, что я имею дело с «дважды закодированным» текстом utf8 из внешнего файла. Чтобы продемонстрировать эту проблему, я создал текстовый файл «test.txt» со следующими символами Unicode в одной строке: U + 00e8, U + 00ab, U + 0086, U + 000a. Эти символы Unicode представляют собой двойную кодировку символа Unicode U + 8acb вместе с символом новой строки. Файл был закодирован на диск в UTF8. Затем я запускаю следующий Perl-скрипт:
#!/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";
Это дает следующий вывод:
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
Это то, что я ожидал. Первоначально длина равна 7, потому что perl считает, что $ test - это просто последовательность байтов. После однократного декодирования Perl знает, что $ test - это серия символов, которые кодируются в utf8 (то есть вместо того, чтобы возвращать длину в 7 байтов, perl возвращает длину в 4 символа, хотя $ test по-прежнему составляет 7 байт в памяти). После второго декодирования $ test содержит 4 байта, интерпретируемых как 2 символа, что я и ожидал, так как Encode :: decode взял 4 кодовых пункта и интерпретировал их как байты в кодировке utf8, что привело к 2 символам. Странная вещь, когда я изменяю код, чтобы вместо этого вызывать utf8 :: decode (заменить все $ test = Encode :: decode ("utf8", $ test); на utf8 :: decode ($ test))
Это дает почти идентичный вывод, отличается только результат длины:
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
Кажется, что perl сначала подсчитывает байты перед декодированием (как и ожидалось), затем подсчитывает символы после первого декодирования, но затем снова подсчитывает байты после второго декодирования (не ожидается). Почему это произошло? Есть ли ошибка в моем понимании того, как работают эти функции декодирования?
Спасибо,
Matt