web-dev-qa-db-fra.com

Remplacer les caractères non-ASCII par un seul espace

Je dois remplacer tous les caractères non-ASCII (\ x00-\x7F) par un espace. Je suis surpris que cela ne soit pas chose facile en Python, à moins que quelque chose me manque. 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 le nombre d'espaces correspondant au nombre d'octets dans le point de code de caractère (c'est-à-dire que 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?

OfthemyriadofsimilaireSOquestions , rienadressecaractèreremplacementas - opposétostrip-tease , et s'adresse en outre à tous les caractères non-ascii et non à un caractère spécifique.

219
dotancohen

Votre expression ''.join() est filtrage, supprimant tout élément non ASCII; vous pouvez utiliser une expression conditionnelle à la place:

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

Ceci gère les caractères un par un et utilise toujours un espace par caractère remplacé.

Votre expression régulière doit simplement remplacer consécutif caractères non-ASCII par un espace:

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

Notez le + ici.

218
Martijn Pieters

Pour que vous obteniez la représentation la plus semblable de votre chaîne d'origine, je vous recommande le module unidecode :

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

Ensuite, vous pouvez l'utiliser dans une chaîne:

remove_non_ascii("Ceñía")
Cenia
46
Alvaro Fuentes

Pour le traitement caractère, utilisez 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 (séparez les caractères et combinez les 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'
19
Mark Tolonen

Si le personnage de remplacement peut être '?' au lieu d'un espace, alors 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
8
AXO

Qu'en est-il de 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
7
parsecer

En tant qu'approche native et efficace, vous n'avez pas besoin d'utiliser ord ni aucune boucle sur les caractères. Il suffit d’encoder avec ascii et d’ignorer les erreurs.

Ce qui suit supprimera simplement les caractères non-ASCII:

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

Maintenant, si vous voulez remplacer les caractères supprimés, procédez comme suit:

final_string = new_string + b' ' * (len(old_string) - len(new_string))
2
Kasrâmvd