2012-02-24 17 views
7

Perché questa stampa è una U e non una Ü?Qual è il modo giusto per ottenere un grapheme?

#!/usr/bin/env perl 
use warnings; 
use 5.014; 
use utf8; 
binmode STDOUT, ':utf8'; 
use charnames qw(:full); 

my $string = "\N{LATIN CAPITAL LETTER U}\N{COMBINING DIAERESIS}"; 

while ($string =~ /(\X)/g) { 
     say $1; 
} 

# Output: U 
+0

it [funziona] (http://ideone.com/tw9Qr) su perl 5.12. – jfs

+6

Hai bisogno di giocare queste cose con i numeri; non fidatevi di ciò che un "terminale" mostra. Passa attraverso [uniquote] (http://training.perl.com/scripts/uniquote), probabilmente con '-x' o' -v', e guarda cosa sta facendo. Gli occhi ingannano, e i programmi sono anche peggio. Il tuo programma terminale è bacato, quindi ti sta mentendo. – tchrist

risposta

3

questo funziona per me, anche se ho una vecchia versione di Perl, 5.012, su ubuntu. La mia unica modifica allo script è: use 5.012;

$ perl so.pl 
Ü 
+0

uso 5.010; fa anche il lavoro. Testato su Ubuntu con perl 5.012; –

+0

Non ha funzionato con 'Konsole' (2.7.2) da KDE. Ora l'ho provato con 'xterm' e lì ha funzionato. –

1

Posso suggerire che sia l'uscita che non è corretto? E 'facile da controllare: sostituire il codice di ciclo con:

my $counter; 
while ($string =~ /(\X)/g) { 
    say ++$counter, ': ', $1; 
} 

... e cercare quante volte l'espressione regolare corrisponderà. La mia ipotesi continuerà a combaciare solo una volta.

In alternativa, è possibile utilizzare questo codice:

use Encode; 
sub codepoint_hex { 
    sprintf "%04x", ord Encode::decode("UTF-8", shift); 
} 

... e quindi stampare codepoint_hex ($ 1) invece del semplice $ 1 entro il ciclo while.

+0

Non dovresti quasi mai chiamare codifica/decodifica per favore. – tchrist

+0

Non capisco perché dovrei decodificare la partita. –

+0

@sid_com Non dovresti, ovviamente. – tchrist

1

1) Apparentemente, il terminale non è in grado di visualizzare caratteri estesi. Su mio terminale, esso stampa:

2)\X non fa quello che pensi lo fa. Seleziona semplicemente i personaggi che vanno insieme. Se si utilizza la stringa "fu\N{COMBINING DIAERESIS}r", il programma visualizza:

f 
u¨ 
r 

Si noti come il contrassegno diacritico non viene stampata da solo, ma con il suo carattere corrispondente.

3) Per combinare tutti i personaggi legati in uno, utilizzare il modulo Unicode::Normalize:

use Unicode::Normalize; 

my $string = "fu\N{COMBINING DIAERESIS}r"; 
$string = NFC($string); 

while ($string =~ /(\X)/g) { 
    say $1; 
} 

Esso mostra:

f 
ü 
r 
+1

** PRIMO: ** Questo non è ciò che fa NFC. Capita semplicemente di farlo qui. Fa molte altre cose; le persone si sbagliano riguardo al suo uso e scopo generale. ** SECONDO: ** Se il tuo programma terminale non visualizza correttamente i caratteri combinati, sta trattando sequenze canonicamente equivalenti in modo diverso, il che è male e sbagliato. Vedere Requisito di conformità C6 a p.60 dello standard Unicode. Il tuo è buggy: non dovresti averlo bisogno, altrimenti non puoi scrivere: 'perl -CS -Mutf8 -MUnicode :: Normalize -E 'dire scalare reverse NFD (" crème brûlée ")'' => 'éelurb emerc'. – tchrist

+1

Si noti che l'esecuzione di NFC su "éelurb emerc" non "combina tutti i caratteri correlati in uno". – tchrist

+1

Cosa pensi che pensi '\ X'? – tchrist

8

Il vostro codice è corretto.

Hai davvero bisogno di giocare queste cose con i numeri; non fidatevi di ciò che un "terminale" mostra. Passa attraverso the uniquote program, probabilmente con -x o -v, e guarda cosa sta facendo.

Gli occhi ingannano e i programmi sono anche peggio. Il tuo programma terminale è bacato, quindi ti sta mentendo. La normalizzazione non dovrebbe avere importanza.

$ perl -CS -Mutf8 -MUnicode::Normalize -E 'say "crème brûlée"' 
crème brûlée 
$ perl -CS -Mutf8 -MUnicode::Normalize -E 'say "crème brûlée"' | uniquote -x 
cr\x{E8}me br\x{FB}l\x{E9}e 
$ perl -CS -Mutf8 -MUnicode::Normalize -E 'say NFD "crème brûlée"' 
crème brûlée 
$ perl -CS -Mutf8 -MUnicode::Normalize -E 'say NFD "crème brûlée"' | uniquote -x 
cre\x{300}me bru\x{302}le\x{301}e 

$ perl -CS -Mutf8 -MUnicode::Normalize -E 'say NFC scalar reverse NFD "crème brûlée"' 
éel̂urb em̀erc 
$ perl -CS -Mutf8 -MUnicode::Normalize -E 'say NFC scalar reverse NFD "crème brûlée")' | uniquote -x 
\x{E9}el\x{302}urb em\x{300}erc 
$ perl -CS -Mutf8 -MUnicode::Normalize -E 'say scalar reverse NFD "crème brûlée"' 
éel̂urb em̀erc 
$ perl -CS -Mutf8 -MUnicode::Normalize -E 'say scalar reverse NFD "crème brûlée"' | uniquote -x 
e\x{301}el\x{302}urb em\x{300}erc 
+0

Concordo. Non sono richieste modifiche al codice. È un problema con il terminale dell'OP (e anche il mio, 'konsole' di Debian's KDE). – ikegami

Problemi correlati