Buscar..


Observaciones

Una advertencia sobre la codificación de nombre de archivo


Cabe mencionar que la codificación de nombre de archivo no solo es específica de la plataforma, sino también del sistema de archivos .

Nunca es completamente seguro asumir (pero a menudo lo es) que solo porque puede codificar y escribir en un nombre de archivo dado, que cuando más tarde intente abrir ese mismo nombre de archivo para leer, aún se llamará la misma cosa.

Por ejemplo, si escribe en un sistema de archivos como FAT16 que no admite Unicode, sus nombres de archivo podrían traducirse silenciosamente a formularios compatibles con ASCII.

Pero es aún menos seguro suponer que un archivo que puede crear, leer y escribir con nombres explícitos se llamará de la misma manera cuando se lo solicite a través de otras llamadas, por ejemplo, readdir puede devolver diferentes bytes para su nombre de archivo de los que especificó para open .

En algunos sistemas, como VAX, ni siquiera puede asumir siempre que readdir devolverá el mismo nombre de archivo que especificó con open para los nombres de archivo tan simple como foo.bar , ya que las extensiones de nombre de archivo pueden ser modificadas por el sistema operativo.

Además, en UNIX, hay un conjunto muy liberal de caracteres legales para los nombres de archivo que permite el sistema operativo, excluyendo solo / y \0 , donde, como en Windows, hay rangos específicos de caracteres que están prohibidos en los nombres de archivo y causarán errores.

Ejercer mucha precaución aquí, evitar trucos de fantasía con los nombres de archivo, si usted tiene una opción, y siempre tienen pruebas para asegurarse de que los trucos de fantasía que usted hace uso son consistentes.

Tenga mucho cuidado si está escribiendo código destinado a ejecutarse en plataformas fuera de su control, como si está escribiendo código destinado a CPAN , y suponga que al menos el 5% de su base de usuarios se atascará con algunos Tecnología antigua o rota, ya sea por elección, por accidente o por poderes fuera de su control, y que estos conspirarán para crear errores para ellos.

: encoding (utf8) vs: utf8


Dado que UTF-8 es uno de los formatos internos para la representación de cadenas en Perl, el paso de codificación / decodificación a menudo se puede omitir. En lugar de :encoding(utf-8) , simplemente puede usar :utf8 , si sus datos ya están en UTF-8. :utf8 puede usarse de forma segura con flujos de salida, mientras que para el flujo de entrada puede ser peligroso, ya que causa una inconsistencia interna cuando tiene secuencias de bytes no válidas. Además, el uso de :utf8 para la entrada puede dar lugar a violaciones de seguridad, por lo que se recomienda el uso de :encoding(utf-8) .

Más detalles: ¿Cuál es la diferencia entre: codificación y: utf8

UTF-8 vs utf8 vs UTF8


A partir de Perl v5.8.7 , "UTF-8" (con guión) significa UTF-8 en su forma estricta y consciente de la seguridad, mientras que "utf8" significa UTF-8 en su forma liberal y holgada.

Por ejemplo, "utf8" se puede usar para puntos de código que no existen en Unicode, como 0xFFFFFFFF . Correspondientemente, las secuencias de bytes UTF-8 no válidas como "\x{FE}\x{83}\x{BF}\x{BF}\x{BF}\x{BF}\x{BF}" se decodificarán en una 0xFFFFFFFF código Unicode no válido (pero Perl válido) ( 0xFFFFFFFF ) cuando se utiliza "utf8" , mientras que la "UTF-8" no permitiría la decodificación a puntos de código fuera del rango de Unicode válido y le daría un carácter de sustitución ( 0xFFFD ).

Dado que los nombres de codificación no distinguen entre mayúsculas y minúsculas, "UTF8" es lo mismo que "utf8" (es decir , variante no estricta ).

Más detalles: UTF-8 vs. utf8 vs. UTF8

Más lectura


Los detalles sobre el manejo de Perl en Unicode se describen con más detalle en las siguientes fuentes:

Publicaciones de stackoverflow.com (advertencia: podría no estar actualizado):

Videos de Youtube:

Crear nombres de archivos

Los siguientes ejemplos utilizan la codificación UTF-8 para representar nombres de archivos (y nombres de directorio) en el disco. Si desea utilizar otra codificación, debe usar Encode::encode(...) .

use v5.14;
# Make Perl recognize UTF-8 encoded characters in literal strings.
# For this to work: Make sure your text-editor is using UTF-8, so
# that bytes on disk are really UTF-8 encoded.
use utf8;

# Ensure that possible error messages printed to screen are converted to UTF-8.
# For this to work: Check that your terminal emulator is using UTF-8.
binmode STDOUT, ':utf8';
binmode STDERR, ':utf8';
    
my $filename = 'æ€'; # $filename is now an internally UTF-8 encoded string. 

# Note: in the following it is assumed that $filename has the internal UTF-8
#  flag set, if $filename is pure ASCII, it will also work since its encoding
#  overlaps with UTF-8. However, if it has another encoding like extended ASCII,
#  $filename will be written with that encoding and not UTF-8. 
# Note: it is not necessary to encode $filename as UTF-8 here
#  since Perl is using UTF-8 as its internal encoding of $filename already

# Example1  -- using open()
open ( my $fh, '>', $filename ) or die "Could not open '$filename': $!";
close $fh;

# Example2 -- using qx() and touch
qx{touch $filename};

# Example3 -- using system() and touch
system 'touch', $filename;

# Example4 -- using File::Touch
use File::Touch;
eval { touch( $filename ) }; die "Could not create file '$filename': $!" if $@;

Leer nombres de archivos

Perl no intenta decodificar los nombres de archivos devueltos por las funciones integradas o los módulos. Tales cadenas que representan nombres de archivos siempre deben decodificarse explícitamente, para que Perl los reconozca como Unicode.

use v5.14;
use Encode qw(decode_utf8);

# Ensure that possible error messages printed to screen are converted to UTF-8.
# For this to work: Check that you terminal emulator is using UTF-8.
binmode STDOUT, ':utf8';
binmode STDERR, ':utf8';

# Example1  -- using readdir()
my $dir = '.';
opendir(my $dh, $dir) or die "Could not open directory '$dir': $!";
while (my $filename = decode_utf8(readdir $dh)) {
    # Do something with $filename
}
close $dh;

# Example2  -- using getcwd()
use Cwd qw(getcwd);
my $dir = decode_utf8( getcwd() );

# Example3  -- using abs2rel()
use File::Spec;
use utf8;
my $base = 'ø';
my $path = "$base/b/æ";
my $relpath = decode_utf8( File::Spec->abs2rel( $path, $base ) );
# Note: If you omit $base, you need to encode $path first:
use Encode qw(encode_utf8);
my $relpath = decode_utf8( File::Spec->abs2rel( encode_utf8( $path ) ) );

# Example4  -- using File::Find::Rule (part1 matching a filename)
use File::Find::Rule;
use utf8;
use Encode qw(encode_utf8);
my $filename = 'æ';
# File::Find::Rule needs $filename to be encoded
my @files = File::Find::Rule->new->name( encode_utf8($filename) )->in('.');
$_ = decode_utf8( $_ ) for @files;

# Example5  -- using File::Find::Rule (part2 matching a regular expression)
use File::Find::Rule;
use utf8;
my $pat = '[æ].$'; # Unicode pattern
# Note: In this case:  File::Find::Rule->new->name( qr/$pat/ )->in('.')
#  will not work since $pat is Unicode and filenames are bytes
#  Also encoding $pat first will not work correctly
my @files;
File::Find::Rule->new->exec( sub { wanted( $pat, \@files ) } )->in('.');
$_ = decode_utf8( $_ ) for @files;
sub wanted {
    my ( $pat, $files ) = @_;
    my $name = decode_utf8( $_ );
    my $full_name = decode_utf8( $File::Find::name );
    push @$files, $full_name if $name =~ /$pat/;
}

Nota: si le preocupa el UTF-8 no válido en los nombres de archivo, el uso de decode_utf8( ... ) en los ejemplos anteriores probablemente debería ser reemplazado por decode( 'utf-8', ... ) . Esto se debe a que decode_utf8( ... ) es un sinónimo de decode( 'utf8', ... ) y existe una diferencia entre las codificaciones utf-8 y utf8 (consulte las Notas a continuación para obtener más información) donde utf-8 es más estricto en lo que es aceptable que utf8 .

Interruptores de línea de comando para one-liners

Habilitar pragma utf8

Para habilitar pragma utf8 en one-liner, se debe llamar al intérprete perl con la opción -Mutf8 :

perl -Mutf8 -E 'my $人 = "human"; say $人'

Manejo de Unicode con interruptor -C

El indicador de línea de comando -C permite controlar las funciones de Unicode. Puede ir seguido de una lista de letras opcionales.

E / S estándar

  • I - STDIN estará en UTF-8
  • O - STDOUT estará en UTF-8
  • E - STDERR estará en UTF-8
  • S - taquigrafía para IOE , las secuencias de E / S estándar estarán en UTF-8
echo "Ματαιότης ματαιοτήτων" | perl -CS -Mutf8 -nE 'say "ok" if /Ματαιότης/'

Argumentos del guión

  • A : trata a @ARGV como una matriz de cadenas codificadas en UTF-8
perl -CA -Mutf8 -E 'my $arg = shift; say "anteater" if $arg eq "муравьед"' муравьед

Capa PerlIO predeterminada

  • i - UTF-8 es la capa PerlIO predeterminada para las secuencias de entrada
  • o - UTF-8 es la capa PerlIO predeterminada para las secuencias de salida
  • D - taquigrafía para io
perl -CD -Mutf8 -e 'open my $fh, ">", "utf8.txt" or die $!; print $fh "개미 조심해"'

-M interruptores -M y -C se pueden combinar:

perl -CASD -Mutf8 -E 'say "Ματαιότης ματαιοτήτων\n"';

E / S estándar

La codificación que se utilizará para los identificadores de binmode E / S estándar ( STDIN , STDOUT y STDERR ) se puede configurar por separado para cada identificador utilizando binmode :

binmode STDIN, ':encoding(utf-8)';
binmode STDOUT, ':utf8';
binmode STDERR, ':utf8';

Nota: cuando se lee uno, en general, se prefiere :encoding(utf-8) sobre :utf8 , consulte Observaciones para obtener más información.

Alternativamente, puede utilizar el pragma open .

# Setup such that all subsequently opened input streams will use ':encoding(utf-8)'
# and all subsequently opened output streams will use ':utf8'
# by default
use open (IN => ':encoding(utf-8)', OUT => ':utf8');
# Make the (already opened) standard file handles inherit the setting 
# given by the IO settings for the open pragma
use open ( :std );
# Now, STDIN has been converted to ':encoding(utf-8)', and 
# STDOUT and STDERR have ':utf8'

Alternativamente, para configurar todos los identificadores de archivo (tanto los que aún no se han abierto como los estándar) para usar :encoding(utf-8) :

use open qw( :encoding(utf-8) :std );

Manijas de archivo

Configuración de la codificación con Open ()

Al abrir un archivo de texto, puede especificar su codificación explícitamente con un open() tres argumentos open() . Este en- / decodificador adjunto a un identificador de archivo se llama "capa de E / S":

my $filename = '/path/to/file';
open my $fh, '<:encoding(utf-8)', $filename or die "Failed to open $filename: $!";

Vea Observaciones para una discusión de las diferencias entre :utf8 y :encoding(utf-8) .

Configuración de la codificación con binmode ()

Alternativamente, puede usar binmode () para establecer la codificación para el identificador de archivo individual:

my $filename = '/path/to/file';
open my $fh, '<', $filename or die "Failed to open $filename: $!";
binmode $fh, ':encoding(utf-8)';

pragma abierto

Para evitar establecer la codificación para cada identificador de archivo por separado, puede usar el pragma open para establecer una capa de E / S predeterminada utilizada por todas las llamadas subsiguientes a la función open() y operadores similares dentro del alcance léxico de este pragma:

# Set input streams to ':encoding(utf-8)' and output streams to ':utf8'
use open (IN => ':encoding(utf-8)', OUT => ':utf8');
# Or to set all input and output streams to ':encoding(utf-8)'
use open ':encoding(utf-8)';

Configuración de la codificación con la línea de comando -C bandera

Finalmente, también es posible ejecutar el intérprete perl con un indicador -CD que aplica UTF-8 como la capa de E / S predeterminada. Sin embargo, esta opción debe evitarse, ya que se basa en un comportamiento específico del usuario que no se puede predecir ni controlar.

El pragma utf8: usando Unicode en tus fuentes

El pragma utf8 indica que el código fuente se interpretará como UTF-8. Por supuesto, esto solo funcionará si su editor de texto también guarda la fuente como codificación UTF-8.

Ahora, los literales de cadena pueden contener caracteres Unicode arbitrarios; los identificadores también pueden contener caracteres Unicode pero solo de tipo palabra (consulte perldata y perlrecharclass para obtener más información):

use utf8;
my $var1 = '§я§©😄';      # works fine
my $я = 4;                # works since я is a word (matches \w) character
my $p§2 = 3;              # does not work since § is not a word character.
say "ya" if $var1 =~ /я§/; # works fine (prints "ya")

Nota : al imprimir texto en el terminal, asegúrese de que sea compatible con UTF-8. *

Puede haber relaciones complejas y contraintuitivas entre la salida y la codificación de origen. Al ejecutarse en una terminal UTF-8, puede encontrar que agregar el pragma utf8 parece romper las cosas:

$ perl -e 'print "Møøse\n"'
Møøse
$ perl -Mutf8 -e 'print "Møøse\n"'
M��se
$ perl -Mutf8 -CO -e 'print "Møøse\n"'
Møøse

En el primer caso, Perl trata la cadena como bytes en bruto y los imprime así. Como estos bytes son UTF-8 válidos, se ven correctos aunque Perl realmente no sabe qué caracteres son (por ejemplo, la length("Møøse") devolverá 7, no 5). Una vez que agrega -Mutf8 , Perl decodifica correctamente la fuente UTF-8 en caracteres, pero la salida está en modo Latin-1 por defecto y la impresión de Latin-1 en un terminal UTF-8 no funciona. Solo cuando cambie STDOUT a UTF-8 usando -CO , la salida será correcta.

use utf8 no afecta la codificación de E / S estándar ni los manejadores de archivos!

Manejo de UTF-8 inválido

Lectura inválida de UTF-8

Al leer datos codificados en UTF-8, es importante tener en cuenta el hecho de que los datos codificados en UTF-8 pueden ser inválidos o mal formados. Dichos datos generalmente no deberían ser aceptados por su programa (a menos que sepa lo que está haciendo). Cuando se encuentran datos malformados inesperadamente, se pueden considerar diferentes acciones:

  • Imprima el seguimiento de pila o el mensaje de error, y cancele el programa correctamente, o
  • Inserte un carácter de sustitución en el lugar donde apareció la secuencia de bytes con formato incorrecto, imprima un mensaje de advertencia a STDERR y continúe leyendo mientras no sucede nada.

Por defecto, Perl le warn acerca de la codificación de fallos, pero no abortará su programa. Puede hacer que su programa aborte haciendo que las advertencias de UTF-8 sean fatales, pero tenga en cuenta las advertencias en Advertencias fatales .

El siguiente ejemplo escribe 3 bytes en la codificación ISO 8859-1 al disco. A continuación, intenta volver a leer los bytes de nuevo como datos codificados en UTF-8. Uno de los bytes, 0xE5 , es una secuencia de un byte UTF-8 no válida:

use strict;
use warnings;
use warnings FATAL => 'utf8';

binmode STDOUT, ':utf8';
binmode STDERR, ':utf8';
my $bytes = "\x{61}\x{E5}\x{61}";  # 3 bytes in iso 8859-1: aåa
my $fn = 'test.txt';
open ( my $fh, '>:raw', $fn ) or die "Could not open file '$fn': $!";
print $fh $bytes;
close $fh;
open ( $fh, "<:encoding(utf-8)", $fn ) or die "Could not open file '$fn': $!";
my $str = do { local $/; <$fh> };
close $fh;
print "Read string: '$str'\n";

El programa abortará con una advertencia fatal:

utf8 "\xE5" does not map to Unicode at ./test.pl line 10.

La línea 10 es aquí la segunda última línea, y el error se produce en la parte de la línea con <$fh> cuando se intenta leer una línea del archivo.

Si no hace que las advertencias sean fatales en el programa anterior, Perl seguirá imprimiendo la advertencia. Sin embargo, en este caso, intentará recuperarse del byte 0xE5 con formato incorrecto insertando los cuatro caracteres \xE5 en el flujo y luego continuará con el siguiente byte. Como resultado, el programa imprimirá:

Read string: 'a\xE5a'


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow