Quelle est la meilleure façon de supprimer les accents dans une chaîne unicode Python?

j'ai une chaîne Unicode en Python, et je voudrais enlever tous les accents (diacritiques).

j'ai trouvé sur le Web une façon élégante de faire ceci en Java:

  1. convertir la chaîne Unicode à sa longue forme normalisée (avec un caractère distinct pour les lettres et les signes diacritiques)
  2. supprimer tous les caractères dont le type Unicode est"diacritique".

ai-je besoin pour installer une bibliothèque comme pyICU ou est-ce possible seulement avec la bibliothèque standard de python? Et que dire de python 3?

Note importante: je voudrais éviter le code avec une mise en correspondance explicite des caractères accentués à leur contrepartie non accentuée.

361
demandé sur Mark Amery 2009-02-06 00:10:40

9 réponses

Unidecode est la bonne réponse pour cela. Il translittère n'importe quelle chaîne unicode dans la représentation la plus proche possible dans le texte ascii.

exemple:

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'
284
répondu Christian Oudard 2017-07-21 17:23:40

Que pensez-vous de ceci:

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

cela fonctionne sur les lettres grecques, aussi:

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

la catégorie de caractères "Mn" signifie Nonspacing_Mark , qui est similaire à unicodedata.combinaison dans la réponse de MiniQuark (Je n'ai pas pensé à unicodedata.la combinaison, mais c'est probablement la meilleure solution, parce que c'est plus explicite).

et gardez à l'Esprit, ces manipulations peuvent modifier de manière significative la signification du texte. Les Accents, les Trémas, etc. ne sont pas des "décoration".

230
répondu oefe 2016-07-28 13:39:51

je viens de trouver cette réponse sur le 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

ça marche bien (pour le français, par exemple), mais je pense que la deuxième étape (enlever les accents) pourrait être mieux gérée que de laisser tomber les caractères non-ASCII, parce que cela échouera pour certaines langues (le grec, par exemple). La meilleure solution serait probablement de supprimer explicitement les caractères unicode étiquetés comme étant diacritiques.

Modifier : ce le truc:

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) renvoie true si le caractère c peut être combiné avec le caractère précédent, c'est surtout si c'est un diacritique.

Edit 2 : remove_accents s'attend à un unicode chaîne de caractères, pas une chaîne d'octets. Si vous avez une chaîne d'octets, alors vous devez décoder une chaîne unicode comme ceci:

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)
120
répondu MiniQuark 2015-09-14 17:01:00

en fait, je travaille sur les projets python 2.6, 2.7 et 3.4 compatibles et je dois créer des ID à partir d'entrées utilisateur Libres.

grâce à vous, j'ai créé cette fonction qui fait des merveilles.

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

résultat:

text_to_id("Montréal, über, 12.89, Mère, Françoise, noël, 889")
>>> 'montreal_uber_1289_mere_francoise_noel_889'
21
répondu Jer42 2017-11-23 22:12:14

il ne traite pas seulement les accents, mais aussi les" traits " (comme dans ø 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)

C'est la façon la plus élégante à laquelle je puisse penser (et elle a été mentionnée par alexis dans un commentaire sur cette page), bien que je ne pense pas qu'elle soit très élégante en effet.

il y a encore des lettres spéciales qui ne sont pas traitées par cela, comme les lettres tournées et inversées, puisque leur nom unicode ne contient pas 'avec'. Ça dépend de ce que tu veux faire de toute façon. J'ai parfois eu besoin de strippage d'accent pour réaliser l'ordre de tri du dictionnaire.

12
répondu lenz 2013-03-21 12:39:18

en réponse à la réponse de @MiniQuark:

j'ai essayé de lire dans un fichier csv qui était à moitié français (contenant des accents) et aussi quelques chaînes qui deviendraient éventuellement des entiers et des flotteurs. Comme test, j'ai créé un fichier test.txt qui ressemblait à ceci:

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

j'ai dû inclure les lignes 2 et 3 travail (que j'ai trouvé dans un billet python), ainsi que d'incorporer le commentaire 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)

le résultat:

Montreal
uber
12.89
Mere
Francoise
noel
889

(Note: je suis sur Mac OS X 10.8.4 et j'utilise Python 2.7.3)

11
répondu aseagram 2013-06-12 18:10:05
import unicodedata
s = 'Émission'
search_string = ''.join((c for c in unicodedata.normalize('NFD', s) if unicodedata.category(c) != 'Mn'))

Pour Python 3.X

print (search_string)

Pour Python 2.X

print search_string
8
répondu Rajan Mandanka 2017-03-01 20:40:12

gensim.utils.deaccent(texte) à partir de Gensim - sujet " modélisation pour l'homme :

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

une autre solution est unidecode .

non pas que la solution suggérée avec unicodedata enlève typiquement les accents seulement dans un certain caractère (par exemple , il tourne 'ł' en '' , plutôt que dans 'l' ).

6
répondu Piotr Migdal 2018-01-30 00:27:58

certaines langues combinent des signes diacritiques comme Lettres de langue et des signes diacritiques d'accent pour spécifier l'accent.

je pense qu'il est plus sûr de spécifier explicitement ce que diactrics vous voulez enlever:

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))
1
répondu sirex 2015-07-24 11:34:02