Reemplazar caracteres no ASCII con un solo espacio


Necesito reemplazar todos los caracteres no ASCII (\x00-\x7F) con un espacio. Me sorprende que esto no sea del todo fácil en Python, a menos que me esté perdiendo algo. La siguiente función simplemente elimina todos los caracteres no ASCII:

def remove_non_ascii_1(text):

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

Y este reemplaza caracteres no ASCII con la cantidad de espacios según la cantidad de bytes en el punto de código de caracteres (es decir, el carácter se reemplaza con 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?

De el una miríada de de similar ASÍ preguntas, ninguno dirección carácter reemplazo como se opuso a a pelar, y además de la dirección de todos los caracteres que no son ascii no un carácter específico.

Author: Community, 2013-11-19

6 answers

Su expresión ''.join() es filtrando , eliminando cualquier cosa que no sea ASCII; podría usar una expresión condicional en su lugar:

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

Esto maneja caracteres uno por uno y todavía usaría un espacio por carácter reemplazado.

Su expresión regular solo debe reemplazar caracteres consecutivos no ASCII con un espacio:

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

Note el + allí.

 178
Author: Martijn Pieters,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-19 18:11:35

Para obtener la representación más similar 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
 32
Author: Alvaro Fuentes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-22 17:58:00

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 todavía tendrá un problema si su cadena contiene caracteres Unicode descompuestos (caracteres separados 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'
 17
Author: Mark Tolonen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-19 21:26:15

Si el carácter de reemplazo puede ser '?'en lugar de un espacio, entonces yo 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
 6
Author: AXO,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-03 11:12:33

¿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
 4
Author: parsecer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-20 22:35:18

Como un enfoque nativo y eficiente, no es necesario utilizar ord o cualquier bucle sobre los caracteres. Simplemente codifique con ascii e ignore 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, haga lo siguiente:

final_string = new_string + b' ' * (len(old_string) - len(new_string))
 1
Author: Kasrâmvd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-23 14:39:32