2017-02-11 2 views
6

Следующий сценарий кодируется в UTF-8:Почему umlaut не распознается в кодировке Perl с кодировкой UTF-8 с использованием «utf8»?

use utf8; 

$fuer = pack('H*', '66c3bc72'); 

$fuer =~ s/ü/!!!/; 

print $fuer; 

ü в s/// хранятся в сценарии, как c3 bc, как следующий дамп показывает xxd шестигранных.

0000000: 75 73 65 20 75 74 66 38 3b 0a 0a 24 66 75 65 72 use utf8;..$fuer 
0000010: 20 3d 20 70 61 63 6b 28 27 48 2a 27 2c 20 27 36 = pack('H*', '6 
0000020: 36 63 33 62 63 37 32 27 29 3b 0a 0a 24 66 75 65 6c3bc72');..$fue 
0000030: 72 20 3d 7e 20 73 2f c3 bc 2f 21 21 21 2f 3b 0a r =~ s/../!!!/;. 
0000040: 0a 70 72 69 6e 74 20 24 66 75 65 72 3b 0a  .print $fuer;. 

c3 bc является представление UTF-8 для ü.

Поскольку сценарий кодируется в UTF-8, и я use ING utf8, я ожидал, что сценарий для замены für в переменной $fuer - но это не делает.

Это, однако, если я удалю use utf8. Это противоречит тому, что я думал use utf8: для указания того, что сценарий закодирован в UTF-8.

ответ

9

Проблема с границами символов. Вы сравниваете кодированные строки байт с расшифрованной строкой символов

$fuer = pack('H*', '66c3bc72') создает четыре-байтовое строку "\x66\xc3\xbc\x72", в то время как маленькие у с диэрезисом ü является "\xfc" поэтому два не совпадают

Если вы использовали decode_utf8 от Encode модуля, чтобы дополнительно обработать переменную $fuer, то он будет декодировать UTF-8, чтобы сформировать строку из трех символов "\x66\xfc\x72", и замена затем работать

use utf8 применяются эквивалентом decode_utf8 к исходному файлу всего, поэтому без него ваш ü появляется кодируются в "\xc3\xbc", который соответствует упакованной переменной

+1

Спасибо за ответ - Это первый раз, я считаю, (надеюсь ...), что я понимаю, 'use utf8'.Кроме того, я не знал, что Perl имеет концепцию границ символов. Я всегда думал, что строка - это просто (и только) массив байтов. Отсюда моя путаница. –

4

Давайте выйти на ü из s/// и в своей собственной переменной, чтобы мы могли проверить его.

use utf8;        # Script is encoded using UTF-8 
use open ':std', ':encoding(UTF-8)'; # Terminal expects UTF-8. 

use strict; 
use warnings; 

my $uuml = "ü"; 
printf("%d %vX %s", length($uuml), $uuml, $uuml); # 1 FC ü 

my $fuer = pack('H*', '66c3bc72'); 
printf("%d %vX %s", length($fuer), $fuer, $fuer); # 4 66.C3.BC.72 für 

$fuer =~ s/\Q$uuml/!!!/; 
printf("%d %vX %s", length($fuer), $fuer, $fuer); # 4 66.C3.BC.72 für 

Как это делает очевидным, вы сравниваете код Unicode Точку ü (FC) против кодировки UTF-8 ü (C3 BC).

Да, use utf8; указывает, что сценарий кодируется с использованием UTF-8 ... но он делает это так, что Perl может правильно декодировать скрипт.

Декодировать все входы и кодировать все выходы! Решение состоит в том, чтобы заменить

my $fuer = pack('H*', '66c3bc72'); 

с

use Encode qw(decode_utf8); 

my $fuer = decode_utf8(pack('H*', '66c3bc72')); 

или

my $fuer = pack('H*', '66c3bc72'); 
utf8::decode($fuer); 
Смежные вопросы