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