Remplacer les caractères non ASCII par un espace unique

je dois remplacer tous les caractères non-ASCII (x00-x7F) par un espace. Je suis surpris que ce ne soit pas facile en Python, sauf si je rate quelque chose. La fonction suivante supprime simplement tous les caractères non-ASCII:

def remove_non_ascii_1(text):

    return ''.join(i for i in text if ord(i)<128)

et celui-ci remplace les caractères non ASCII par la quantité d'espaces en fonction de la quantité d'octets dans le point de code de caractère (c.-à-d. le caractère est remplacé par 3 espaces):

def remove_non_ascii_2(text):

    return re.sub(r'[^x00-x7F]',' ', text)

Comment puis-je remplacer tous les caractères non ASCII par un seul espace?

De le myriade de similaires DONC questions , none adresse caractère de remplacement comme opposition à stripping , et en outre l'adresse de tous les caractères non-ascii pas un caractère spécifique.

181
demandé sur Community 2013-11-19 22:09:03

6 réponses

votre expression ''.join() est filtrage , supprimant tout ce qui n'est pas ASCII; vous pouvez utiliser une expression conditionnelle à la place:

return ''.join([i if ord(i) < 128 else ' ' for i in text])

cette commande traite les caractères un par un et utiliserait toujours un espace par caractère remplacé.

votre expression habituelle devrait simplement remplacer consécutif caractères non ASCII avec un espace:

re.sub(r'[^\x00-\x7F]+',' ', text)

Note + là.

178
répondu Martijn Pieters 2013-11-19 18:11:35

pour vous la représentation la plus similaire de votre chaîne originale je recommande le module unidecode :

from unidecode import unidecode
def remove_non_ascii(text):
    return unidecode(unicode(text, encoding = "utf-8"))

, Alors vous pouvez l'utiliser dans une chaîne de caractères:

remove_non_ascii("Ceñía")
Cenia
32
répondu Alvaro Fuentes 2018-02-22 17:58:00

Pour caractère le traitement, l'utilisation des chaînes Unicode:

PythonWin 3.3.0 (v3.3.0:bd8afb90ebf2, Sep 29 2012, 10:57:17) [MSC v.1600 64 bit (AMD64)] on win32.
>>> s='ABC马克def'
>>> import re
>>> re.sub(r'[^\x00-\x7f]',r' ',s)   # Each char is a Unicode codepoint.
'ABC  def'
>>> b = s.encode('utf8')
>>> re.sub(rb'[^\x00-\x7f]',rb' ',b) # Each char is a 3-byte UTF-8 sequence.
b'ABC      def'

mais notez que vous aurez toujours un problème si votre chaîne contient des caractères Unicode décomposés (caractères séparés et combinaison de marques d'accent, par exemple):

>>> s = 'mañana'
>>> len(s)
6
>>> import unicodedata as ud
>>> n=ud.normalize('NFD',s)
>>> n
'mañana'
>>> len(n)
7
>>> re.sub(r'[^\x00-\x7f]',r' ',s) # single codepoint
'ma ana'
>>> re.sub(r'[^\x00-\x7f]',r' ',n) # only combining mark replaced
'man ana'
17
répondu Mark Tolonen 2013-11-19 21:26:15

Si le caractère de remplacement peut être"?'au lieu d'un espace, je suggérerais result = text.encode('ascii', 'replace').decode() :

"""Test the performance of different non-ASCII replacement methods."""


import re
from timeit import timeit


# 10_000 is typical in the project that I'm working on and most of the text
# is going to be non-ASCII.
text = 'Æ' * 10_000


print(timeit(
    """
result = ''.join([c if ord(c) < 128 else '?' for c in text])
    """,
    number=1000,
    globals=globals(),
))

print(timeit(
    """
result = text.encode('ascii', 'replace').decode()
    """,
    number=1000,
    globals=globals(),
))

Résultats:

0.7208260721400134
0.009975979187503592
6
répondu AXO 2017-01-03 11:12:33

et celui-ci?

def replace_trash(unicode_string):
     for i in range(0, len(unicode_string)):
         try:
             unicode_string[i].encode("ascii")
         except:
              #means it's non-ASCII
              unicode_string=unicode_string[i].replace(" ") #replacing it with a single space
     return unicode_string
4
répondu parsecer 2016-08-20 22:35:18

comme approche native et efficace, vous n'avez pas besoin d'utiliser ord ou n'importe quelle boucle sur les caractères. Il suffit d'encoder avec ascii et d'ignorer les erreurs.

ce qui suit va simplement supprimer les caractères non-ascii:

new_string = old_string.encode('ascii',errors='ignore')

maintenant si vous voulez remplacer les caractères supprimés faites juste ce qui suit:

final_string = new_string + b' ' * (len(old_string) - len(new_string))
1
répondu Kasrâmvd 2018-01-23 14:39:32