2012-05-24 23 views
6

Ho bisogno di normalizzare una stringa come "queo" e non riesco a convertire i caratteri ASCII estesi come é, á, í, ecc in versioni roman/english. Ho provato diversi metodi, ma nulla funziona finora. C'è una buona quantità di materiale su questo argomento generale ma non riesco a trovare una risposta funzionante a questo problema.Normalizzazione caratteri ASCII

Ecco il mio codice:

#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); 
} 

risposta

9

1) Questo article dovrebbe fornire un modo abbastanza buono (se complicata).

Fornisce una soluzione per convertire tutti i caratteri Unicode accentati nel carattere di base + accento; una volta fatto, puoi semplicemente rimuovere i caratteri dell'accento separatamente.


2) Un'altra opzione è CPAN: Text::Unaccent::PurePerl (una versione migliorata Pure Perl di Text::Unaccent)


3) Inoltre, this SO answer propone Text::Unidecode:

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

Soluzione meravigliosa, funziona benissimo !!! Grazie! –

7

Il motivo per cui il tuo codice originale non funziona è t il cappello \x{130} non è é. È LATIN CAPITAL LETTER I WITH DOT ABOVE (U+0130 or İ). Intendevi \x{E9} o solo \xE9 (le parentesi sono facoltative per i numeri a due cifre), LATIN SMALL LETTER E WITH ACUTE (U+00E9).

Inoltre, si dispone di una barra rovesciata in più nel telefono tr; dovrebbe apparire come tr/\xE9/e/.

Con tali modifiche, il codice funzionerà, sebbene raccomando comunque di utilizzare uno dei moduli su CPAN per questo genere di cose. Preferisco lo stesso Text::Unidecode, poiché gestisce molto più dei semplici caratteri accentati.

+1

Grazie per l'aiuto! Ho implementato le tue modifiche e ora funziona. In effetti sto usando un modulo nella versione consegnata poiché sembra essere il modo più elegante, anche se è bello sapere che non ero troppo lontano. –

3

Dopo aver lavorato e lavorato nuovamente, ecco cosa ho ora. Sta facendo tutto quello che voglio, tranne che mi piacerebbe mantenere gli spazi nel mezzo delle stringhe di input per differenziare le parole.

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"; 
} 
Non

del tutto sicuro perché è colorando alcune delle regex e commenti rossi ...

Ecco alcuni esempi di righe di "funnywords.txt":

Quee

22.

? éÉíóñúÑ¿¡

[.questo? ]

aquí, Alli

2

riguarda la seconda domanda di sbarazzarsi di eventuali altri simboli ma mantenendo lettere e numeri cambiano la vostra ultima regex da s/\W+//g a s/[^a-zA-Z0-9 ]+//g. Dal momento che hai già normalizzato il resto dell'input, l'utilizzo di regex rimuoverà tutto ciò che non è a-z, A-Z, 0-9 o spazi bianchi.L'uso di [] e a^all'inizio indicano che si desidera cercare tutto ciò che NON è nel resto della parentesi.

Problemi correlati