2010-06-03 11 views
8

In che modo le stringhe perl sono rappresentate internamente? Quale codifica viene utilizzata? Come gestisco correttamente le diverse codifiche?Interni di stringhe Perl

Utilizzo perl da molto tempo, ma non includeva molta gestione delle stringhe in codifiche diverse e quando ho riscontrato un problema minore che aveva a che fare con le codifiche, di solito ricorrevo ad alcune azioni sciamaniche.

Fino a questo momento ho pensato a stringhe perl come sequenze di byte, che si adattavano bene ai miei compiti. Ora ho bisogno di fare un po 'di elaborazione del file con codifica UTF-8 e qui iniziano i problemi.

In primo luogo, ho letto file in stringa come questa:

open(my $in, '<', $ARGV[0]) or die "cannot open file $ARGV[0] for reading"; 
binmode($in, ':utf8'); 

my $contents; 

{ 
    local $/; 
    $contents = <$in>; 
} 

close($in); 

poi semplicemente stamparlo:

print $contents; 

e ottengo due cose: un avvertimento Wide character in print at <scriptname> line <n> e un bidone della spazzatura in consolle. Quindi posso concludere che le stringhe di perl hanno un concetto di "carattere" che può essere "ampio" o no, ma quando vengono stampati questi caratteri "larghi" sono rappresentati in console come byte multipli, non come singoli "caratteri". (Mi chiedo ora perché tutta la mia precedente esperienza con i file binari ha funzionato abbastanza come mi aspettavo che funzionasse senza problemi di "carattere").

Perché poi vedo la spazzatura in console? Se perl memorizza stringhe come carattere in alcune codifiche conosciute, non penso che ci sia un grosso problema a scoprire la codifica della console e stampare correttamente il testo. (Io uso Windows, BTW).

Se perl memorizza stringhe come sequenze di caratteri a larghezza variabile (ad esempio utilizzando la stessa codifica UTF-8), perché viene eseguita in questo modo? Dalla mia esperienza di gestione delle stringhe C è il dolore.

Aggiornamento.

Io uso due computer per il test, uno esegue Windows 7 x64 con il language pack inglese installato, ma con le impostazioni regionali russe (quindi ho cp866 come codepage OEM e cp1251 come ANSI) con ActivePerl 5.10.1 x64; un altro esegue localizzazione russa a 32 bit di Windows XP con Cygwin Perl 5.10.0.

Grazie ai collegamenti, ora ho una comprensione molto più solida su cosa sta succedendo e su come le cose dovrebbero essere fatte.

risposta

4

L'impostazione di utf8 prima della lettura dal file è buona, decodifica automagicamente i byte nella codifica interna. (Che è anche UTF-8 ma non è necessario saperlo, e non dovrebbe fare affidamento su.)

Prima di stampare è necessario codificare i caratteri in byte.

use Encode; 
utf8::encode($contents); 

C'è anche una forma a due argomenti di codifica, per le altre codifiche rispetto all'unicode. (Quella frase echeggia troppo, vero?)

Ecco un buon riferimento. (Sarebbe stato di più, ma è il mio primo post.) Guarda anche perlunitut, e l'articolo unicode su Joel su Software.

http://www.ahinea.com/en/tech/perl-unicode-struggle.html

Oh, ed è necessario utilizzare stringhe multi-byte, perché altrimenti non è solo unicode.

+0

Per stringhe multi-byte intendevo la codifica a larghezza variabile. – n0rd

+0

Ad ogni modo non capisco perché devo fare una conversione esplicita: ho specificato la codifica dei dati di input perché devo fare qualche passo in più? – n0rd

+2

Hai specificato la codifica di input. Fai le tue cose. Quindi si specifica la codifica di output. Gli articoli cui ho fatto riferimento spiegano meglio, dovrei pensare. – dylan

2

Si dovrebbe menzionare le versioni attuali di Windows e Perl in quanto ciò dipende molto dalle versioni utilizzate e dai pacchetti di lingua installati.
hanno Altrimenti uno sguardo al manuale PerlUnicode prima -

Perl utilizza caratteri logicamente ampio per rappresentare le stringhe internamente.

confermerà le vostre dichiarazioni.

Windows non installa completamente tutto il carattere UTF8, quindi questo potrebbe essere il motivo del problema. Potrebbe essere necessario installare un pacchetto linguistico aggiuntivo.

+0

La tua penultima frase non ha assolutamente senso. Sembra che tu faccia riferimento ai caratteri, ma questo non ha nulla a che fare con le codifiche. – daxim

4

Le stringhe Perl sono memorizzate internamente in una delle due codifiche, una codifica nativa a 8 bit orientata ai byte o UTF-8. Per la comparabilità al contrario, l'ipotesi è che tutti gli I/O e le stringhe siano in codifica nativa, se non diversamente specificato. La codifica nativa è in genere ASCII a 8 bit, ma può essere modificata con use locale.

Nell'esempio si chiama binmode sull'impugnatura di input cambiandolo per utilizzare la semantica :utf8. Un effetto di questo è che tutte le stringhe lette da questo handle saranno codificate come UTF-8. print scrive su STDOUT per impostazione predefinita e il valore predefinito è STDOUT che prevede caratteri nativi codificati.

Perl nel tentativo di fare la cosa giusta consentirà di inviare una stringa UTF-8 a un output codificato nativo, ma se non c'è alcuna codifica collegata a quell'handle, allora deve indovinare come emettere multi-byte personaggi e quasi certamente indovina. Questo è ciò che significa l'avvertimento, un carattere multi-byte è stato inviato a un flusso che si aspettava solo caratteri a byte singolo e il risultato era che il carattere era probabilmente danneggiato nella traduzione.

seconda di ciò che si vuole realizzare è possibile utilizzare il modulo Encode citato da Dylan per convertire i dati UTF-8 a un set di caratteri singolo byte che può essere stampato in modo sicuro o se si sa che tutto ciò che è collegato a STDOUT in grado di gestire UTF-8 è possibile utilizzare binmode(STDOUT, ':utf8'); per comunicare a Perl che si desidera inviare qualsiasi dato inviato a STDOUT come UTF-8.

+0

Se la codifica defualt era ASCII 8 bit (o qualsiasi altra codifica a 8 bit), perché Perl stampa le stringhe UTF-8 come byte non elaborati (ovvero stampa di due caratteri per console per ogni carattere cirillico nella stringa stampata) invece di stampare il risultato della transcodifica in quella codifica che avrebbe esattamente la stessa quantità di caratteri della stringa originale? – n0rd

+1

@ n0rd una stringa UTF-8 non è byte dalla prospettiva perl, è caratteri. Un risultato strano di questo IIRC è che quando viene stampato su un handle senza codifica definita troncherà i punti di codice Unicode superiori a 255 solo agli 8 bit più bassi. –