https://rt.perl.org/rt3//Public/Bug/Display.html?id=80190

я есть некоторые интересные результаты, пытаясь различить различия между использованием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

Ответы на вопрос(2)

Ваш ответ на вопрос