2017-02-11 35 views
6

skryptu jest zakodowane w UTF-8Dlaczego umlaut nie jest rozpoznawany w skrypcie UTL-8 zakodowanym w Perlu za pomocą "use utf8"?

use utf8; 

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

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

print $fuer; 

ü w s/// jest przechowywany w skrypcie jako c3 bc, jak wynika z poniższego zrzutu xxd sześciokątnych.

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 jest reprezentacją UTF-8 ü.

Ponieważ skrypt jest kodowana w UTF-8 i jestem use ing utf8, spodziewałem skrypt zastąpić für w zmiennej $fuer - jeszcze nie.

Ma to jednak miejsce w przypadku usunięcia use utf8. To działa wbrew temu, co moim zdaniem było use utf8: wskazać, że skrypt jest zakodowany w UTF-8.

Odpowiedz

9

Problem dotyczy granic postaci. Porównujesz zakodowany ciąg bajtów z zdekodowanej ciąg znaków

$fuer = pack('H*', '66c3bc72') tworzy ciąg czterech bajtów "\x66\xc3\xbc\x72", natomiast mała u z diaeresis ü jest "\xfc" więc dwa nie pasują

Jeśli użyto decode_utf8 z modułu Encode do dalszego przetworzenia zmienna $fuer wtedy byłoby dekodowania UTF-8, aby utworzyć ciąg trzyznakowy "\x66\xfc\x72", a substytutem będzie wtedy pracować

use utf8 obowiązuje równoważny decode_utf8 do pliku źródłowego całego, więc bez niej swój ü pojawia zakodowane jak "\xc3\xbc", która odpowiada zapakowany zmienną

+1

Dzięki za odpowiedź - Jest to pierwszy raz, wierzę (mam nadzieję ...), że rozumiem rzecz 'use utf8'.Nie wiedziałem też, że Perl ma pojęcie granic postaci. Zawsze myślałem, że ciąg jest po prostu (i tylko) tablicą bajtów. Stąd moje zamieszanie. –

4

Przejdźmy się z ü z s/// i do własnej zmiennej, więc możemy go kontrolować.

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 

Jak to sprawia, że ​​oczywiste, jesteś porównując kod Unicode Punkt ü (FC) w stosunku do kodowania UTF-8 ü (C3 BC).

Tak, use utf8; oznacza, że ​​skrypt jest kodowany przy użyciu UTF-8 ... ale robi to tak, że Perl może poprawnie dekodować skrypt.

Dekoduje wszystkie wejścia i koduje wszystkie wyjścia! Rozwiązaniem jest zastąpienie

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

z

use Encode qw(decode_utf8); 

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

lub

my $fuer = pack('H*', '66c3bc72'); 
utf8::decode($fuer); 
Powiązane problemy