2009-08-25 12 views
11

La página perldoc para length() me dice que debo usar bytes::length(EXPR) para encontrar una cadena Unicode en bytes, y la página bytes hace eco de esto.¿Cómo puedo encontrar la longitud de una cadena Unicode en 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"; 

La salida de este script, sin embargo, no está de acuerdo con la página de manual:

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

Me parece longitud() y los bytes :: longitud() devuelven el mismo para ambos ASCII & cadenas Unicode . Tengo mi editor configurado para escribir archivos como UTF-8 de forma predeterminada, así que creo que Perl está interpretando todo el script como Unicode. ¿Eso significa que length() maneja automáticamente las cadenas Unicode correctamente?

Editar: Ver mi comentario; mi pregunta no tiene mucho sentido, porque length() es no trabajando "correctamente" en el ejemplo anterior: muestra la longitud de la cadena Unicode en bytes, no en caracteres. El reson que originalmente tropecé con esto es para un programa en el que necesito establecer el encabezado Content-Lenth (en bytes) en un mensaje HTTP. Había leído en Unicode en Perl y esperaba tener que hacer algo de imaginación para que las cosas funcionaran, pero cuando length() devolvió exactamente lo que necesitaba del bate, ¡estaba confundido! Consulte la respuesta aceptada para obtener una descripción general de use utf8, use bytes y no bytes en Perl.

+0

No veo por qué dices que length() maneja las cadenas Unicode correctamente. En su ejemplo, length() da el mismo resultado que bytes :: length(), que es el número de bytes, no el número de caracteres (que sería el adecuado). – Inshallah

+0

En otras palabras, length ($ unicode) interpreta la cadena como ASCII, no como unicode. – Inshallah

+0

¡Tiene toda la razón! Había pasado por alto por completo este hecho: en mi programa, estoy usando length() para establecer el encabezado Content-Length en un mensaje HTTP, que debe estar en bytes. Después de leer los documentos de longitud(), esperaba que la función devolviera algo incorrecto, pero de hecho es exactamente lo que quiero cuando Perl está en el modo 'use bytes': la longitud de la cadena Unicode en bytes, en lugar de caracteres. –

Respuesta

21

Si sus scripts están codificados en UTF-8, utilice el utf8 pragma. El bytes pragma por otro lado forzará la semántica de bytes en la longitud, incluso si la cadena es UTF-8. Ambos funcionan en el alcance léxico actual.

$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"; 

Este salidas:

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

El propósito de la bytes pragma es reemplazar la función length (y varias otras funciones relacionadas con la cuerda) en el ámbito actual. Así que cada llamada a length en su programa es una llamada al length que proporciona bytes. Esto está más en línea con lo que estaba tratando de hacer:

#!/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"; 

Otro defecto sutil en su razonamiento es que no hay tal cosa como bytes Unicode. Unicode es una enumeración de caracteres. Dice, por ejemplo, que U + 24d5 es & # x24d5 (PEQUEÑA LETRA LATINA CIRCULADA F); Lo que Unicode no especifica cuántos bytes ocupa un personaje. Eso queda en las codificaciones. UTF-8 dice que ocupa 3 bytes, UTF-16 dice que ocupa 2 bytes, UTF-32 dice que requiere 4 bytes, etc. Aquí está comparison of Unicode encodings. Perl usa UTF-8 para sus cadenas por defecto. UTF-8 tiene la ventaja de ser idéntico en todos los sentidos a ASCII para los primeros 127 caracteres.

1

Encontré que es posible utilizar el módulo Encode para influir en cómo funciona la longitud.

si $ string es una cadena con codificación utf8.

Codificar :: _ utf8_on ($ cadena); # la función de longitud mostrará la cantidad de puntos de código después de esto.

Encode :: _ utf8_off ($ string); # la función de longitud mostrará el número de bytes en la cadena después de esto.

Cuestiones relacionadas