2012-05-24 20 views
6

Necesito normalizar una cadena como "quée" y no puedo convertir los caracteres ASCII extendidos como é, á, í, etc. en versiones roman/inglés. He intentado varios métodos diferentes pero nada funciona hasta ahora. Hay una buena cantidad de material sobre este tema general, pero parece que no puedo encontrar una respuesta funcional a este problema.Normalización de caracteres ASCII

Aquí está mi código:

#transliteration solution (works great with standard chars but doesn't find the 
#special ones) - I've tried looking for both \x{130} and é with the same result. 
$mystring =~ tr/\\x{130}/e/; 

#converting into array, then iterating through and replacing the specific char 
#(same result as the above solution) 
my @breakdown = split("",$mystring); 

foreach (@breakdown) { 
    if ($_ eq "\x{130}") { 
     $_ = "e"; 
     print "\nArray Output: @breakdown\n"; 
    } 
    $lowercase = join("",@breakdown); 
} 

Respuesta

9

1) Este article debe proporcionar una manera bastante buena (si se complica).

Proporciona una solución para convertir todos los caracteres Unicode acentuados en el carácter base + acento; una vez hecho esto, simplemente puede eliminar los caracteres de acento por separado.


2) Otra opción es CPAN: Text::Unaccent::PurePerl (Una versión mejorada puro Perl de Text::Unaccent)


3) Además, this SO answer propone Text::Unidecode:

$ perl -Mutf8 -MText::Unidecode -E 'say unidecode("été")' 
    ete 
+0

¡Solución maravillosa, funciona genial! ¡Gracias! –

7

La razón por la cual su código original no funciona es t sombrero \x{130} no es é. Es LATIN CAPITAL LETTER I WITH DOT ABOVE (U+0130 or İ). Querías decir \x{E9} o solo \xE9 (las llaves son opcionales para números de dos dígitos), LATIN SMALL LETTER E WITH ACUTE (U+00E9).

Además, tiene una barra invertida adicional en su tr; debería verse como tr/\xE9/e/.

Con esos cambios, su código funcionará, aunque aún recomendaría usar uno de los módulos en CPAN para este tipo de cosas. Prefiero Text::Unidecode para esto, ya que maneja mucho más que solo caracteres acentuados.

+1

¡Gracias por la ayuda! Implementé tus cambios y funciona ahora. De hecho, estoy usando un módulo en la versión entregada, ya que parece ser la manera más elegante, aunque es bueno saber que no estaba muy lejos. –

3

Después de trabajar y volver a trabajar, esto es lo que tengo ahora. Está haciendo todo lo que quiero, excepto que me gustaría mantener espacios en medio de cadenas de entrada para diferenciar entre palabras.

open FILE, "funnywords.txt"; 

# Iterate through funnywords.txt 
while (<FILE>) { 
    chomp; 

    # Show initial text from file 
    print "In: '$_' -> "; 

    my $inputString = $_; 

    # $inputString is scoped within a for each loop which dissects 
    # unicode characters (example: "é" splits into "e" and "´") 
    # and throws away accent marks. Also replaces all 
    # non-alphanumeric characters with spaces and removes 
    # extraneous periods and spaces. 
    for ($inputString) { 
     $inputString = NFD($inputString); # decompose/dissect 
     s/^\s//; s/\s$//;     # strip begin/end spaces 
     s/\pM//g;       # strip odd pieces 
     s/\W+//g;       # strip non-word chars 
    } 

    # Convert to lowercase 
    my $outputString = "\L$inputString"; 

    # Output final result 
    print "$outputString\n"; 
} 
No

del todo seguro de por qué está colorear algunas de las expresiones regulares y comentarios rojas ...

Éstos son algunos ejemplos de líneas de "funnywords.txt":

quee

22.

? éÉíóñúÑ¿¡

[.Esta? ]

Aquí, Alli

2

Para su segunda pregunta acerca de cómo deshacerse de los símbolos restantes, pero manteniendo las letras y los números cambian su última expresión regular de s/\W+//g a s/[^a-zA-Z0-9 ]+//g. Como ya ha normalizado el resto de la entrada, usar esa expresión regular eliminará todo lo que no sea a-z, A-Z, 0-9 o espacios en blanco.El uso de [] y a^al comienzo indicará que desea buscar todo lo que NO está en el resto del corchete.

Cuestiones relacionadas