2009-08-25 3 views
11

Die perldoc Seite für length() sagt mir, dass ich bytes::length(EXPR) verwenden sollte, um eine Unicode-Zeichenfolge in Bytes zu finden, und die bytes-Seite echo dies.Wie finde ich die Länge einer Unicode-Zeichenfolge in Perl?

use bytes; 
$ascii = 'Lorem ipsum dolor sit amet'; 
$unicode = 'Lørëm ípsüm dölör sît åmét'; 

print "ASCII: " . length($ascii) . "\n"; 
print "ASCII bytes: " . bytes::length($ascii) . "\n"; 
print "Unicode: " . length($unicode) . "\n"; 
print "Unicode bytes: " . bytes::length($unicode) . "\n"; 

Die Ausgabe dieses Skripts jedoch nicht mit der Man-Page:

ASCII: 26 
ASCII bytes: 26 
Unicode: 35 
Unicode bytes: 35 

Es scheint mir, Länge() und Bytes :: Länge() geben die gleiche für beide ASCII & Unicode-Strings . Ich habe meinen Editor so eingestellt, dass Dateien standardmäßig als UTF-8 geschrieben werden, also denke ich, dass Perl das ganze Skript als Unicode interpretiert - bedeutet das, dass length() Unicode-Strings automatisch korrekt behandelt?

Bearbeiten: Siehe meinen Kommentar; meine Frage macht nicht viel Sinn, denn length() ist nicht funktioniert "richtig" im obigen Beispiel - es zeigt die Länge der Unicode-Zeichenfolge in Bytes, nicht Zeichen. Der Resonator, über den ich ursprünglich gestolpert bin, ist für ein Programm, in dem ich den Content-Lenth-Header (in Bytes) in einer HTTP-Nachricht setzen muss. Ich hatte in Perl über Unicode gelesen und rechnete damit, dass ich etwas Geschick machen musste, um die Dinge zum Laufen zu bringen, aber als length() genau das zurückgab, was ich rechts vom Schläger brauchte, war ich verwirrt! Siehe die akzeptierte Antwort für eine Übersicht über use utf8, use bytes und no bytes in Perl.

+0

Ich sehe nicht, warum Sie die Länge sagen() richtig Unicode-Strings behandelt. In Ihrem Beispiel gibt length() dasselbe Ergebnis wie bytes :: length() an, das ist die Anzahl der Bytes, nicht die Anzahl der Zeichen (was richtig wäre). – Inshallah

+0

Mit anderen Worten interpretiert Länge ($ Unicode) die Zeichenfolge als ASCII, nicht als Unicode. – Inshallah

+0

Sie sind absolut richtig! Ich hatte diese Tatsache völlig übersehen - in meinem Programm verwende ich length(), um den Content-Length-Header in einer HTTP-Nachricht zu setzen, die in Bytes sein muss. die Länge() docs Nach der Lektüre, ich habe erwartet, dass die Funktion etwas falsch zurück, aber es ist genau in der Tat, was ich will, wenn Perl ist in 'verwenden bytes' Modus: die Länge des Unicode-String in Bytes, anstatt Zeichen. –

Antwort

21

Wenn Ihre Skripts in UTF-8 codiert sind, verwenden Sie bitte die utf8 pragma. Die bytes pragma andererseits wird Byte-Semantik auf Länge zwingen, selbst wenn die Zeichenfolge UTF-8 ist. Beide arbeiten im aktuellen lexikalischen Bereich.

$ascii = 'Lorem ipsum dolor sit amet'; 
{ 
    use utf8; 
    $unicode = 'Lørëm ípsüm dölör sît åmét'; 
} 
$not_unicode = 'Lørëm ípsüm dölör sît åmét'; 

no bytes; # default, can be omitted 
print "Character semantics:\n"; 

print "ASCII: ", length($ascii), "\n"; 
print "Unicode: ", length($unicode), "\n"; 
print "Not-Unicode: ", length($not_unicode), "\n"; 

print "----\n"; 

use bytes; 
print "Byte semantics:\n"; 

print "ASCII: ", length($ascii), "\n"; 
print "Unicode: ", length($unicode), "\n"; 
print "Not-Unicode: ", length($not_unicode), "\n"; 

Diese Ausgänge:

Character semantics: 
ASCII: 26 
Unicode: 26 
Not-Unicode: 35 
---- 
Byte semantics: 
ASCII: 26 
Unicode: 35 
Not-Unicode: 35 
4

Der Zweck des bytes pragma ist die length Funktion (und einige andere Zeichenkette verwandte Funktionen) im aktuellen Rahmen zu ersetzen. Also jeder Anruf an length in Ihrem Programm ist ein Anruf an die length, die bytes bietet. Dies ist mehr im Einklang mit dem, was Sie zu tun haben versucht:

#!/usr/bin/perl 

use strict; 
use warnings; 

sub bytes($) { 
    use bytes; 
    return length shift; 
} 

my $ascii = "foo"; #really UTF-8, but everything is in the ASCII range 
my $utf8 = "\x{24d5}\x{24de}\x{24de}"; 

print "[$ascii] characters: ", length $ascii, "\n", 
    "[$ascii] bytes  : ", bytes $ascii, "\n", 
    "[$utf8] characters: ", length $utf8, "\n", 
    "[$utf8] bytes  : ", bytes $utf8, "\n"; 

Ein weiterer subtiler Fehler in Ihrer Argumentation ist, dass es so etwas wie Unicode Byte. Unicode ist eine Aufzählung von Zeichen. Es heißt zum Beispiel, dass die U + 24d5 & # x24d5 (CIRCLED LATIN SMALL LETTER F) ist; Was Unicode nicht angibt, wie viele Bytes ein Zeichen belegt. Das ist den Kodierungen überlassen. UTF-8 sagt, es dauert 3 Bytes, UTF-16 sagt, es dauert 2 Bytes, UTF-32 sagt, es dauert 4 Bytes usw. Hier ist comparison of Unicode encodings. Perl verwendet standardmäßig UTF-8 für seine Zeichenfolgen. UTF-8 hat den Vorteil, dass es für die ersten 127 Zeichen in jeder Hinsicht mit ASCII identisch ist.

1

Ich fand, dass es möglich ist, Encodemodul zu verwenden, um zu beeinflussen, wie die Länge funktioniert.

Wenn $ string ist utf8 codierte Zeichenfolge.

Codierung :: _ utf8_on ($ string); # Die Längenfunktion zeigt danach die Anzahl der Codepunkte an.

Codierung :: _ utf8_off ($ string); # Die Längenfunktion zeigt danach die Anzahl der Bytes in der Zeichenkette an.