¿Por qué no puedo usar la función de mapa para crear un buen hash a partir de un archivo de datos simple en Perl?

StackOverflow https://stackoverflow.com/questions/1762977

  •  21-09-2019
  •  | 
  •  

Pregunta

El puesto se actualiza. Por favor, amablemente saltar a la parte de soluciones, si ya ha leído la pregunta publicada. Gracias!

Este es el código reducido al mínimo para exponer mi problema:

El archivo de datos de entrada para la prueba ha sido salvado por la ventana de una función de Bloc de notas como codificación UTF-8. Tiene las tres líneas siguientes:

abacus  æbәkәs
abalone æbәlәuni
abandon әbændәn

El archivo de script Perl también ha sido salvado por la ventana de una función de Bloc de notas como codificación UTF-8. Contiene el siguiente código:

#!perl -w

use Data::Dumper;
use strict;
use autodie;
open my $in,'<',"./hash_test.txt";
open my $out,'>',"./hash_result.txt";

my %hash = map {split/\t/,$_,2} <$in>;
print $out Dumper(\%hash),"\n";
print $out "$hash{abacus}";
print $out "$hash{abalone}";
print $out "$hash{abandon}";

En la salida, la tabla hash parece estar bien:

$VAR1 = {
          'abalone' => 'æbәlәuni
',
          'abandon' => 'әbændәn',
          'abacus' => 'æbәkәs
'
        };

Pero en realidad no lo es, porque solo me dan dos valores en lugar de tres:

æbәlәuni
әbændәn

Perl da el siguiente mensaje de advertencia:

Use of uninitialized value $hash{"abacus"} in string at C:\test2.pl line 11, <$i n> line 3.

¿dónde está el problema? ¿Puede alguien explicar amablemente? Gracias.

La solución

Millones de gracias a todos ustedes :) Ahora, finalmente, el culpable se encuentra y se puede arreglar el problema se vuelve :) Como @Sinan perspicacia señaló, ahora estoy 100% seguro de que el culpable de causar el problema que he descrito anteriormente es los dos bytes de lista de materiales, que el Bloc de notas añadido a mi archivo de datos cuando se guardó como UTF-8 y que de alguna manera Perl no trata adecuadamente. Aunque muchos sugirieron que debería utilizar "<: UTF-8" y ">: UTF-8" para leer y escribir archivos, la cosa es que estas configuraciones utf8 no resuelven el problema. En su lugar, pueden causar otros problemas.

Para resolver realmente el problema, en realidad todo lo que necesito es añadir una línea de código para forzar Perl hacer caso omiso de la lista de materiales:

#!perl -w

use Data::Dumper;
use strict;
use autodie;

open my $in,'<',"./hash_test.txt";
open my $out,'>',"./hash_result.txt";

seek $in,3,0; # force Perl to ignore the BOM!
my %hash = map {split/\t/,$_,2} <$in>;
print $out Dumper(\%hash);
print $out $hash{abacus};
print $out $hash{abalone};
print $out $hash{abandon};

Ahora, la salida es exactamente lo que esperaba:

$VAR1 = {
          'abalone' => 'æbәlәuni
',
          'abandon' => 'әbændәn',
          'abacus' => 'æbәkәs
'
        };
æbәkәs
æbәlәuni
әbændәn

Tenga en cuenta la secuencia de comandos se guarda como codificación UTF-8 y el código no tiene que incluir todas las etiquetas UTF-8 debido a que el archivo de entrada y el archivo de salida son a la vez guardado previamente como codificación UTF-8.

Por último, gracias de nuevo a todos ustedes. Y gracias, @Sinan, para la orientación perspicaz. Sin su ayuda, me quedaría en la oscuridad durante Dios sabe cuánto tiempo.

Nota: Para aclarar un poco más, si uso:

open my $in,'<:utf8',"./hash_test.txt";
open my $out,'>:utf8',"./hash_result.txt";

my %hash = map {split/\t/,$_,2} <$in>;
print $out Dumper(\%hash);
print $out $hash{abacus};
print $out $hash{abalone};
print $out $hash{abandon};

La salida es la siguiente:

$VAR1 = {
          'abalone' => "\x{e6}b\x{4d9}l\x{4d9}uni
",
          'abandon' => "\x{4d9}b\x{e6}nd\x{4d9}n",
          "\x{feff}abacus" => "\x{e6}b\x{4d9}k\x{4d9}s
"
        };
æbәlәuni
әbændәn

Y el mensaje de advertencia:

Use of uninitialized value in print at C:\hash_test.pl line 13,  line 3.
¿Fue útil?

Solución

Me parece que el mensaje de advertencia un poco sospechoso. Se da a conocer que el gestor de archivo $in está en la línea 3, cuando debería ser en la línea 4, después de haber leído la última línea.

Cuando probé el código, he salvado el archivo de entrada utilizando GVim que se configura en mi sistema para guardar como UTF-8, no vi el problema. Ahora que he probado con el Bloc de notas, mirando el archivo de salida, veo:

"\x{feff}abacus" => "\x{e6}b\x{4d9}k\x{4d9}s
"

donde \x{feff} es la BOM .

En la salida Volquete, no está en blanco espuria antes abacus (donde no había especificado :utf8 para el mango de salida).

Como ya había mencionado inicialmente (perdió a las ediciones incontables de esta entrada - gracias a los recordatorios Hobbs)., Especifique '<:utf8' al abrir el archivo de entrada

Otros consejos

Si desea leer archivos UTF8 / escritura, usted debe asegurarse de que en realidad se está leyendo en ellos como UTF8 .

#! /usr/bin/env perl
use Data::Dumper;
open my $in,  '<:utf8', "hash_test.txt";
open my $out, '>:utf8', "hash_result.txt";

my %hash = map { chomp; split ' ', $_, 2 } <$in>;
print $out Dumper(\%hash),"\n";
print $out "$hash{abacus}\n";
print $out "$hash{abalone}\n";
print $out "$hash{abandon}\n";

Si usted quiere que sea más robusto, se recomienda utilizar :encoding(utf8) en lugar de :utf8, para la lectura de un archivo.

open my $in, '<:encoding(utf8)', "hash_test.txt";

PerlIO para más información.

Creo que su respuesta puede estar sentado justo en frente de usted. La salida de Data::Dumper la que usted envió es:

$VAR1 = {
          'abalone' => 'æbәlәuni
',
          'abandon' => 'әbændәn',
          'abacus' => 'æbәkәs
'
        };

Tenga en cuenta el carácter entre el ' y abacus? Ha intentado acceder al tercer valor a través de $hash{abacus}. Esto es incorrecto, debido a que el personaje antes de abacus en el hash Dumper(). Usted podría intentar conectarlo a un bucle que debe cuidar de él:

foreach my $k (keys %hash) {
  print $out $hash{$k};
}

Split / \ s / en lugar de split / \ t /

funciona para mí. ¿Seguro tu ejemplo coincide con el código actual y los datos?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top