У вас две проблемы.
Ваши звонки на pack
неверны
Каждый H
представляет один шестнадцатеричный ди git.
$ perl -e'printf "%vX\n", pack("HH", "D0", "B4")' # XXX
D0.B0
$ perl -e'printf "%vX\n", pack("H2H2", "D0", "B4")' # Ok
D0.B4
$ perl -e'printf "%vX\n", pack("(H2)2", "D0", "B4")' # Ok
D0.B4
$ perl -e'printf "%vX\n", pack("(H2)*", "D0", "B4")' # Better
D0.B4
$ perl -e'printf "%vX\n", pack("H*", "D0B4")' # Alternative
D0.B4
STDOUT ожидает декодированный текст, но вы предоставляете закодированный текст
Сначала давайте взглянем на строки, которые вы создаете (как только проблема указанное выше исправлено). Все, что вам для этого нужно, - это формат %vX
, который предоставляет значение каждого символа в шестнадцатеричном формате, разделенное точкой.
"д"
создает односимвольную строку. Этот символ является кодовой точкой Unicode для д
.
$ perl -e'use utf8; printf("%vX\n", "д");'
434
pack("H*", "D0B4")
создает двухсимвольную строку. Эти символы представляют собой кодировку UTF-8 д
.
$ perl -e'printf("%vX\n", pack("H*", "D0B4"));'
D0.B4
pack("H*", "0434")
создает двухсимвольную строку. Эти символы являются кодировками UCS-2be и UTF-16be д
.
$ perl -e'printf("%vX\n", pack("H*", "0434"));'
4.34
Обычно дескриптор файла ожидает строку байтов (символов со значениями в 0 .. 255) быть напечатанным к нему. Эти байты дословно выводятся. [1] [2]
Когда слой кодирования (например, :encoding(UTF-8)
) добавляется к дескриптору файла, он ожидает Вместо него должна быть напечатана строка кодовых точек Unicode (он же декодированный текст).
Ваша программа добавляет слой кодирования к STDOUT
(используя прагму use open
), поэтому вы должны предоставить UCP (декодированный текст) до print
и say
. Вы можете получить декодированный текст из закодированного текста, используя, например, функцию Encode decode
.
use utf8;
use open qw( :std :encoding(UTF-8) );
use feature qw( say );
use Encode qw( decode );
say "д"; # ok (UCP of "д")
say pack("H*", "D0B4"); # XXX (UTF-8 encoding of "д")
say pack("H*", "0434"); # XXX (UCS-2be and UTF-16be encoding of "д")
say decode("UTF-8", pack("H*", "D0B4")); # ok (UCP of "д")
say decode("UCS-2be", pack("H*", "0434")); # ok (UCP of "д")
say decode("UTF-16be", pack("H*", "0434")); # ok (UCP of "д")
Для случая UTF-8 мне нужно установить UTF -8 флаг на
Нет, вам нужно декодировать строки.
Флаг UTF-8 не имеет значения. Установлен флаг или нет изначально не имеет значения. Установлен флаг или нет после того, как строка декодирована, не имеет значения. Флаг указывает, как строка хранится внутри, что вас не должно волновать.
Например, возьмите
use strict;
use warnings;
use open qw( :std :encoding(UTF-8) );
use feature qw( say );
my $x = chr(0xE9);
utf8::downgrade($x); # Tell Perl to use the UTF8=0 storage format.
say sprintf "%s %vX %s", utf8::is_utf8($x) ? "UTF8=1" : "UTF8=0", $x, $x;
utf8::upgrade($x); # Tell Perl to use the UTF8=1 storage format.
say sprintf "%s %vX %s", utf8::is_utf8($x) ? "UTF8=1" : "UTF8=0", $x, $x;
Выводит
UTF8=0 E9 é
UTF8=1 E9 é
Независимо от флаг UTF8
выводит кодировку UTF-8 (C3 A9
) предоставленного UCP (U + 00E9).
Я полагаю, это потому, что нет путь для Perl UCS-2 из ISO-8859-1, так что тест, вероятно, является бредом, верно?
В лучшем случае можно использовать эвристику, чтобы угадать, закодирована ли строка используя iso-latin-1 или UCS-2be. Я подозреваю, что можно получить довольно точные результаты (например, те , которые вы получили бы для iso-latin-1 и UTF-8.)
Я не уверен, почему вы подняли iso- latin-1, так как ничто в вашем вопросе не относится к iso-latin-1.
За исключением Windows, где слой :crlf
добавлен в дескрипторы по умолчанию.
Вы получаете предупреждение Wide character
, если вы предоставляете строку, содержащую символ, который не является байтом, и вместо нее выводится кодировка utf8
строки.