separar - string en python
Reemplazar caracteres que no sean ASCII con un solo espacio (6)
Necesito reemplazar todos los caracteres que no sean ASCII (/ x00- / x7F) con un espacio. Me sorprende que esto no sea nada fácil en Python, a menos que me falte algo. La siguiente función simplemente elimina todos los caracteres que no son ASCII:
def remove_non_ascii_1(text):
return ''''.join(i for i in text if ord(i)<128)
Y este reemplaza los caracteres no ASCII con la cantidad de espacios según la cantidad de bytes en el punto de código del carácter (es decir, el carácter –
se reemplaza por 3 espacios):
def remove_non_ascii_2(text):
return re.sub(r''[^/x00-/x7F]'','' '', text)
¿Cómo puedo reemplazar todos los caracteres no ASCII con un solo espacio?
Of the myriad of questions SO similar , none replacement character address as opposed to stripping , and además se dirige a todos los caracteres no ascii que no tienen un carácter específico.
¿Qué hay de este?
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
Como enfoque nativo y eficiente, no es necesario utilizar ord
o cualquier loop sobre los caracteres. Simplemente codifica con ascii
e ignora los errores.
Lo siguiente simplemente eliminará los caracteres no ascii:
new_string = old_string.encode(''ascii'',errors=''ignore'')
Ahora, si desea reemplazar los caracteres eliminados solo haga lo siguiente:
final_string = new_string + b'' '' * (len(old_string) - len(new_string))
Para el procesamiento de caracteres , use cadenas 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''
Pero tenga en cuenta que aún tendrá un problema si su cadena contiene caracteres Unicode descompuestos (carácter separado y combinación de acentos, por ejemplo):
>>> 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''
Para usted, obtenga la representación más parecida de su cadena original. Recomiendo el módulo unidecode :
from unidecode import unidecode
def remove_non_ascii(text):
return unidecode(unicode(text, encoding = "utf-8"))
Entonces puedes usarlo en una cadena:
remove_non_ascii("Ceñía")
Cenia
Si el personaje de reemplazo puede ser ''?'' en lugar de un espacio, sugeriría 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(),
))
Resultados:
0.7208260721400134
0.009975979187503592
Su expresión ''''.join()
está filtrando , eliminando todo lo que no sea ASCII; podrías usar una expresión condicional en su lugar:
return ''''.join([i if ord(i) < 128 else '' '' for i in text])
Esto maneja los caracteres uno por uno y todavía usaría un espacio por personaje reemplazado.
Su expresión regular debería reemplazar a los caracteres no ASCII consecutivos con un espacio:
re.sub(r''[^/x00-/x7F]+'','' '', text)
Tenga en cuenta el +
allí.