Domanda

Ho una stringa Unicode in Python, e vorrei togliere tutti gli accenti (segni diacritici).

Ho trovato sul Web un modo elegante per fare questo in Java:

  1. convertire la stringa Unicode per la sua lunga forma normalizzata (con un carattere separato per le lettere e i segni diacritici)
  2. rimuovere tutti i caratteri di cui Unicode tipo di "dieresi".

Devo installare una libreria come pyICU o questo è possibile solo con il python standard library?E che dire di python 3?

Nota importante:Vorrei evitare di codice con un mapping esplicito da caratteri accentati non accentati controparte.

È stato utile?

Soluzione

Unidecode è la risposta giusta per questo. Si traslittera qualsiasi stringa Unicode nella rappresentazione più vicino possibile in testo ASCII.

Esempio:

accented_string = u'Málaga'
# accented_string is of type 'unicode'
import unidecode
unaccented_string = unidecode.unidecode(accented_string)
# unaccented_string contains 'Malaga'and is of type 'str'

Altri suggerimenti

Che ne dite di questo:

import unicodedata
def strip_accents(s):
   return ''.join(c for c in unicodedata.normalize('NFD', s)
                  if unicodedata.category(c) != 'Mn')

Questo funziona su lettere greche, troppo:

>>> strip_accents(u"A \u00c0 \u0394 \u038E")
u'A A \u0394 \u03a5'
>>> 

Il categoria carattere "Mn" sta per Nonspacing_Mark, che è simile a unicodedata.combining in risposta di MiniQuark (non ho pensato di unicodedata.combining, ma è probabilmente la soluzione migliore, perché è più esplicito).

E tenere a mente, queste manipolazioni possono alterare in modo significativo il significato del testo. Accenti, dieresi, ecc non sono "decorazione".

Ho appena trovato questa risposta sul Web:

import unicodedata

def remove_accents(input_str):
    nfkd_form = unicodedata.normalize('NFKD', input_str)
    only_ascii = nfkd_form.encode('ASCII', 'ignore')
    return only_ascii

Funziona bene (per il francese, per esempio), ma penso che il secondo passo (rimuovendo gli accenti) potrebbe essere gestita meglio che cadere i caratteri non-ASCII, perché questa avrà esito negativo per alcune lingue (greco, per esempio) . La soluzione migliore sarebbe probabilmente per rimuovere in modo esplicito i caratteri Unicode che sono contrassegnati come segni diacritici.

Modifica : questo fa il trucco:

import unicodedata

def remove_accents(input_str):
    nfkd_form = unicodedata.normalize('NFKD', input_str)
    return u"".join([c for c in nfkd_form if not unicodedata.combining(c)])

unicodedata.combining(c) restituirà true se il carattere c può essere combinato con il carattere precedente, cioè soprattutto se si tratta di un diacritico.

Modifica 2 : remove_accents si aspetta un unicode stringa, non una stringa di byte. Se si dispone di una stringa di byte, quindi è necessario decodificarlo in una stringa unicode in questo modo:

encoding = "utf-8" # or iso-8859-15, or cp1252, or whatever encoding you use
byte_string = b"café"  # or simply "café" before python 3.
unicode_string = byte_string.decode(encoding)

In realtà ho lavorare sul progetto di pitone compatibile 2.6, 2.7 e 3.4 e devo creare ID di voci utente libero.

Grazie a te, ho creato questa funzione che fa miracoli.

import re
import unicodedata

def strip_accents(text):
    """
    Strip accents from input String.

    :param text: The input string.
    :type text: String.

    :returns: The processed String.
    :rtype: String.
    """
    try:
        text = unicode(text, 'utf-8')
    except (TypeError, NameError): # unicode is a default on python 3 
        pass
    text = unicodedata.normalize('NFD', text)
    text = text.encode('ascii', 'ignore')
    text = text.decode("utf-8")
    return str(text)

def text_to_id(text):
    """
    Convert input text to id.

    :param text: The input string.
    :type text: String.

    :returns: The processed String.
    :rtype: String.
    """
    text = strip_accents(text.lower())
    text = re.sub('[ ]+', '_', text)
    text = re.sub('[^0-9a-zA-Z_-]', '', text)
    return text

Risultati:

text_to_id("Montréal, über, 12.89, Mère, Françoise, noël, 889")
>>> 'montreal_uber_1289_mere_francoise_noel_889'

Questo non solo utilizza gli accenti, ma anche "colpi" (come in ø ecc.):

import unicodedata as ud

def rmdiacritics(char):
    '''
    Return the base character of char, by "removing" any
    diacritics like accents or curls and strokes and the like.
    '''
    desc = ud.name(unicode(char))
    cutoff = desc.find(' WITH ')
    if cutoff != -1:
        desc = desc[:cutoff]
    return ud.lookup(desc)

Questo è il modo più elegante che posso pensare (ed è stata menzionata da alexis in un commento in questa pagina), anche se non credo che è davvero molto elegante.

Ci sono ancora lettere speciali che non sono gestiti da questa, come le lettere tornite e dall'alto in basso, dal momento che il loro nome unicode non contiene 'CON'. Dipende da cosa si vuole fare in ogni caso. A volte mi serviva accento nudo per il raggiungimento di un sistema di classificazione dizionario.

In risposta a @ risposta di MiniQuark:

stavo cercando di leggere in un file CSV che era (gli accenti che contengono) metà francese e anche alcune stringhe che sarebbe poi diventato interi e carri allegorici. Come prova, ho creato un file test.txt che si presentava così:

  

Montréal, über, 12.89, Mère, Françoise, Noël, 889

ho dovuto includere linee 2 e 3 per farlo funzionare (che ho trovato in un biglietto di pitone), così come incorporare @ commento di Jabba:

import sys 
reload(sys) 
sys.setdefaultencoding("utf-8")
import csv
import unicodedata

def remove_accents(input_str):
    nkfd_form = unicodedata.normalize('NFKD', unicode(input_str))
    return u"".join([c for c in nkfd_form if not unicodedata.combining(c)])

with open('test.txt') as f:
    read = csv.reader(f)
    for row in read:
        for element in row:
            print remove_accents(element)

Il risultato:

Montreal
uber
12.89
Mere
Francoise
noel
889

(Nota: Sono su Mac OS X 10.8.4 e l'utilizzo di Python 2.7.3)

gensim.utils.deaccent(testo) da Gensim - argomento di modellazione per gli esseri umani:

deaccent("Šéf chomutovských komunistů dostal poštou bílý prášek") 'Sef chomutovskych komunistu dostal postou bily prasek'

Un'altra soluzione è unidecode.

Non che la soluzione suggerita con unicodedata in genere toglie accenti solo in alcuni caratteri (ad es.si trasforma 'ł' in '', piuttosto che in 'l').

Alcune lingue hanno combinando segni diacritici come lettere linguaggio e segni diacritici accento per specificare accento.

Credo che sia più sicuro di specificare in modo esplicito quello diactrics si vuole mettere a nudo:

def strip_accents(string, accents=('COMBINING ACUTE ACCENT', 'COMBINING GRAVE ACCENT', 'COMBINING TILDE')):
    accents = set(map(unicodedata.lookup, accents))
    chars = [c for c in unicodedata.normalize('NFD', string) if c not in accents]
    return unicodedata.normalize('NFC', ''.join(chars))
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top