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.
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à.
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
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'
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
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
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))