2011-05-05 8 views
5

Tengo un archivo con una frase/términos de cada línea que leí a perl de STDIN. Tengo una lista de palabras vacías (como "á", "são", "é") y quiero comparar cada una de ellas con cada término, y eliminar si son iguales. El problema es que no estoy seguro del formato de codificación del archivo.Perl - Codificación de archivos y comparación de palabras

me sale esto desde el comando file:

words.txt: Non-ISO extended-ASCII English text 

Mi terminal de Linux está en UTF-8 y muestra el contenido correcto para algunas palabras y para otros no lo hacen. Aquí está la salida de algunos de ellos:

condi<E3> 
conte<FA>dos 
ajuda, mas não resolve 
mo<E7>ambique 
pedagógico são fenómenos 

Se puede ver que los días 3 y 5 º líneas están identificando correctamente las palabras con acentos y caracteres especiales, mientras que otros no lo hacen. El resultado correcto para las otras líneas debería ser: condiã, conteúdos y moçambique.

si uso binmode(STDOUT, utf8) las líneas "incorrectas" ahora emite correctamente, mientras que los otros no lo hacen. Por ejemplo, la 3ª línea:

ajuda, mas nà £ o determinación

¿Qué debo hacer chicos?

Respuesta

3

funciona así:

C:\Dev\Perl :: chcp 
Aktive Codepage: 1252. 

C:\Dev\Perl :: type mixed-encoding.txt 
eins zwei drei Käse vier fünf Wurst 
eins zwei drei Käse vier fünf Wurst 

C:\Dev\Perl :: perl mixed-encoding.pl < mixed-encoding.txt 
eins zwei drei vier fünf 
eins zwei drei vier fünf 

Dónde mixed-encoding.pl dice así:

use strict; 
use warnings; 
use utf8; # source in UTF-8 
use Encode 'decode_utf8'; 
use List::MoreUtils 'any'; 

my @stopwords = qw(Käse Wurst); 

while (<>) { # read octets 
    chomp; 
    my @tokens; 
    for (split /\s+/) { 
     # Try UTF-8 first. If that fails, assume legacy Latin-1. 
     my $token = eval { decode_utf8 $_, Encode::FB_CROAK }; 
     $token = $_ if [email protected]; 
     push @tokens, $token unless any { $token eq $_ } @stopwords; 
    } 
    print "@tokens\n"; 
} 

Tenga en cuenta que el guión no tiene que ser codificado en UTF-8. Es que si tiene datos de carácter enrrollados en su script hay que asegurarse de que los partidos de codificación, por lo use utf8 si su codificación es UTF-8, y no lo hacen si no lo es.

de actualización basado en consejos de tchrist:

use strict; 
use warnings; 
# source in Latin1 
use Encode 'decode'; 
use List::MoreUtils 'any'; 

my @stopwords = qw(Käse Wurst); 

while (<>) { # read octets 
     chomp; 
     my @tokens; 
     for (split /\s+/) { 
       # Try UTF-8 first. If that fails, assume 8-bit encoding. 
       my $token = eval { decode utf8 => $_, Encode::FB_CROAK }; 
       $token = decode Windows1252 => $_, Encode::FB_CROAK if [email protected]; 
       push @tokens, uc $token unless any { $token eq $_ } @stopwords; 
     } 
     print "@tokens\n"; 
} 
+0

@ Michael Gracias ahora se ha emitir correctamente;) me di cuenta de que la mayor parte del archivo está en la norma ISO-8859-1 y algunas partes en UTF-8 (por eso algunos de ellos fueron dar salida correctamente) una más cosa. Tengo que usar la función 'lc' porque mis palabras vacías están en mayúsculas y tengo problemas cuando las frases no son utf-8. En estas situaciones, si tengo una letra mayúscula con un acento, no será inferior. – Barata

+2

@Barata: Aún debe decodificar las cadenas que no sean UTF8 si quiere que 'uc' etc. trabaje en ellas. La característica 'Unicode_strings' de Perl 5.12 (y anterior) también puede ayudar, ya que asumirá ISO 8859-1 para cadenas de bytes. Compare: 'perl -e 'print uc (" \ xB5 \ xE9 \ xDF ")'' => 'μéß', ** que es incorrecto, ** con ' perl -M5.012 -e 'print uc ("\ xB5 \ xE9 \ xDF") ''=>' ΜÉSS' ** que es correcto. ** La última cadena es realmente '" \ x {39C} \ x {C9} SS "' o '" \ N { GRIEGO MAYÚSCULA LETRA MU} \ N {LETRA MAYÚSCULA L CON AGUDO} SS "'. La cadena original es '" \ N {MICRO SIGN} \ N {LETRA E MINÚSCULA LATINA CON AGUDO} \ N {LETRA PEQUEÑA LATINA SHARP S} "'. – tchrist

+0

@tchrist ¿Es suficiente usar el código de Michael, verificar 'if $ @' y decodificar la cadena para iso-8859-1? – Barata

4

le recomiendo encarecidamente que crea un filtro que tiene un archivo con líneas en las codificaciones mixtas y las traduce a pura UTF-8. Entonces, en lugar

open(INPUT, "< badstuff.txt") || die "open failed: $!"; 

que abriría ya sea la versión fija, o una tubería desde el fijador, como:

open(INPUT, "fixit < badstuff.txt |") || die "open failed: $!" 

En cualquier caso, lo haría a continuación

binmode(INPUT, ":encoding(UTF-8)") || die "binmode failed"; 

Entonces el fixit programa podría hacer esto:

use strict; 
use warnings; 
use Encode qw(decode FB_CROAK); 

binmode(STDIN, ":raw") || die "can't binmode STDIN"; 
binmode(STDOUT, ":utf8") || die "can't binmode STDOUT"; 

while (my $line = <STDIN>) { 
    $line = eval { decode("UTF-8", $line, FB_CROAK() }; 
    if ([email protected]) { 
     $line = decode("CP1252", $line, FB_CROAK()); # no eval{}! 
    } 
    $line =~ s/\R\z/\n/; # fix raw mode reads 
    print STDOUT $line;  
} 

close(STDIN) || die "can't close STDIN: $!"; 
close(STDOUT) || die "can't close STDOUT: $!"; 
exit 0; 

¿Ves cómo funciona? Por supuesto, puede cambiarlo a la configuración predeterminada a alguna otra codificación, o tener múltiples repliegues. Probablemente sería mejor tomar una lista de ellos en @ARGV.

+0

Muy buen punto para decodificar desde una codificación específica cuando falla la decodificación de UTF-8. Así que no terminas con una mezcla de Unicode y cadenas heredadas, sino que homogeneizas todo a Unicode. – Lumi

Cuestiones relacionadas