2015-06-15 2 views
2

Я пытаюсь понять, как Perl обрабатывает unicode.Создать символ Юникода с пакетом

use feature qw(say); 
use strict; 
use warnings; 

use Encode qw(encode); 

say unpack "H*", pack("U", 0xff); 
say unpack "H*", encode('UTF-8', chr 0xff); 

Выход:

ff 
c3bf 

Почему я получаю ff и не c3bf при использовании пакета?

+0

'упаковка ('U', 0xFF)' является странным способом of 'chr (0xFF)', поэтому неудивительно, что он отличается от 'encode ('UTF-8', chr (0xFF))' – ikegami

ответ

2

Почему я использую пакет ff, а не c3bf?

Это потому, что пакет создает строку символов, а не строку байтов.

> perl -MDevel::Peek -e 'Dump(pack("U", 0xff));' 
SV = PV(0x13a6d18) at 0x13d2ce8 
    REFCNT = 1 
    FLAGS = (PADTMP,POK,READONLY,pPOK,UTF8) 
    PV = 0xa6d298 "\303\277"\0 [UTF8 "\x{ff}"] 
    CUR = 2 
    LEN = 32 

Следовательно распаковать («H *») не смотрит на байт-значение этой строки, но (усеченного) характер значение его. Если бы вы сделали:

say unpack "H*", encode("UTF-8", pack("U", 0xff)); 

Тогда вы получите ожидаемый результат.

См. Также this thread.

+0

Хорошо, поэтому распаковка может обрабатывать только строки байтов (а не строки символов). Было бы интересно узнать, как это усекает, когда ему задана символьная строка, и где это усечение символьных строк документировано? –

+1

распаковка H *, по-видимому, имеет модуль 256 на значениях, я не думаю, что это документировано. Вообще говоря, вы не должны бросать на него какую-либо символьную строку, которая только вызовет горе. –

+0

@Leon Timmermans: «Это потому, что он создает строку символов, а не строку байтов». это полная бессмыслица, и здесь происходит усечение или по модулю 256. Он «распаковывал» («H *», «\ xFF») ', что совершенно законно. – ikegami

2
pack('U', 0xFF) 

просто странный способ сделать

chr(0xFF) 

так

"\xFF"        returns chars FF 
chr(0xFF)       returns chars FF 
pack('U', 0xFF)     returns chars FF 

"\xC3\xBF"       returns chars C3 BF 
encode('UTF-8', chr(0xFF))   returns chars C3 BF 
encode('UTF-8', pack('U', 0xFF)) returns chars C3 BF 

так

say unpack "H*", "\xFF";        outputs ff 
say unpack "H*", chr(0xFF);       outputs ff 
say unpack "H*", pack('U', 0xFF);     outputs ff 

say unpack "H*", "\xC3\xBF";       outputs c3bf 
say unpack "H*", encode('UTF-8', pack('U', 0xFF)); outputs c3bf 
say unpack "H*", encode('UTF-8', chr(0xFF));   outputs c3bf 
+0

Хм, я не уверен, что понимаю. Почему именно 'perl -MDevel :: Peek -e 'Dump (пакет' U ', 0xff),' 'возвращающий' c3bf', тогда как 'perl -MDevel :: Peek -e' Dump (chr 0xff); '' возвращает 'ff'? (Вы говорите, что оба они должны возвращать 'ff' ..) –

+1

' perl -MDevel :: Peek -e 'Dump (пакет' U ', 0xff), '' говорит, что строка '' \ x {ff} "' , 'perl -MDevel :: Peek -e 'Dump (chr 0xff);' 'говорит, что строка' '\ 377" '. В обоих случаях это единственный символ 'FF'. Они хранятся по-разному внутри, но они - одна и та же строка, как и целая нулевая цифра, а нуль с плавающей точкой - равны нулю. – ikegami

+1

'sprintf '% vX', EXPR' покажет вам строку. – ikegami