Pergunta

Eu tenho uma seqüência de caracteres Unicode em Python, e eu gostaria de remover todas as Acentos (diacríticos).

I encontrado na Web uma maneira elegante de fazer isso em Java:

  1. converter a seqüência de caracteres Unicode para sua forma normalizada longa (com um personagem separado para letras e sinais diacríticos)
  2. remover todos os personagens cujo tipo Unicode é "diacrítico".

Do I necessidade de instalar uma biblioteca, como pyICU ou isso é possível apenas com a biblioteca padrão python? E o que dizer python 3?

Nota importante:. Gostaria de código de evitar com um mapeamento explícito de caracteres acentuados à sua contraparte não-acentuado

Foi útil?

Solução

Unidecode é a resposta correta para isso. Ele translitera qualquer seqüência de caracteres Unicode para o mais próximo possível representação em texto ASCII.

Exemplo:

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'

Outras dicas

Como sobre isto:

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

Isso funciona em letras gregas, também:

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

O href="http://www.unicode.org/reports/tr44/#GC_Values_Table" categoria caráter "Mn" significa Nonspacing_Mark, que é semelhante ao unicodedata .combining na resposta de MiniQuark (eu não penso em unicodedata.combining, mas é provavelmente a melhor solução, porque é mais explícito).

E lembre-se, estas manipulações podem alterar significativamente o significado do texto. Acentos, tremas, etc. não são "decoração".

Eu encontrei esta resposta na 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

Ele funciona muito bem (para o francês, por exemplo), mas acho que a segunda etapa (removendo os acentos) poderia ser tratada melhor do que deixar cair os caracteres não-ASCII, porque isso irá falhar por algumas línguas (grego, por exemplo) . A melhor solução seria provavelmente para remover explicitamente os caracteres Unicode que são marcados como sendo sinais diacríticos.

Editar : isso faz o truque:

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) retornará true se o c personagem pode ser combinado com o personagem anterior, que é principalmente se é um sinal diacrítico.

Editar 2 : remove_accents espera um unicode string, não uma seqüência de byte. Se você tem uma cadeia de bytes, então você deve decodificá-lo em uma string unicode assim:

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)

Na verdade, eu trabalho no projeto python compatível 2.6, 2.7 e 3.4 e eu tenho que criar IDs de entradas de usuários livres.

Graças a você, eu criei esta função que faz maravilhas.

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

resultado:

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

Este alças não só acentos, mas também "traços" (como em ø etc.):

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)

Esta é a maneira mais elegante que eu posso pensar (e tem sido mencionado por alexis em um comentário sobre esta página), embora eu não acho que é muito elegante, de fato.

Ainda há letras especiais que não são tratados por este, como cartas virou e invertidas, já que seu nome unicode não contém 'com'. Depende do que você quer fazer de qualquer maneira. Às vezes eu precisava sotaque descascar para alcançar ordem de classificação dicionário.

Em resposta a resposta da @ MiniQuark:

Eu estava tentando ler em um arquivo CSV que era meio francesa (que contêm acentos) e também algumas cordas que acabaria por se tornar inteiros e carros alegóricos. Como um teste, eu criei um arquivo test.txt que ficou assim:

Montréal, über, 12,89, Mère, Françoise, Noel, 889

Eu tive que incluem linhas 2 e 3 para obtê-lo para o trabalho (que eu encontrei em um bilhete de python), bem como incorporar @ comentário de 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)

O resultado:

Montreal
uber
12.89
Mere
Francoise
noel
889

(Nota: Eu estou no Mac OS X 10.8.4 e usando Python 2.7.3)

gensim.utils.deaccent (texto) de Gensim - modelagem tópico para os seres humanos :

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

Outra solução é unidecode .

Não que a solução sugerida com unicodedata tipicamente remove acentos apenas em alguns caracteres (por exemplo, ele se transforma 'ł' em '', ao invés de em 'l').

Algumas línguas têm combinando diacríticos como cartas de línguas e sinais diacríticos acento para especificar sotaque.

Eu acho que é mais seguro para especificar explicitamente o que diactrics você quiser tirar:

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))
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top