Zastąp znaki inne niż ASCII pojedynczym spacją

Muszę zastąpić wszystkie znaki spoza ASCII (\x00-\x7f) spacją. Dziwię się, że w Pythonie nie jest to łatwe, chyba że coś przeoczyłem. Poniższa funkcja po prostu usuwa wszystkie znaki spoza ASCII:

def remove_non_ascii_1(text):

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

I ten Zastępuje znaki nie-ASCII ilością spacji zgodnie z ilością bajtów w punkcie kodu znaku (tzn. znak zastępuje się 3 spacjami):

def remove_non_ascii_2(text):

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

Jak mogę zastąpić wszystkie znaki spoza ASCII pojedyncza przestrzeń?

Z na myriad z podobne więc pytania, Brak adres charakter wymiana jako przeciw na rozbieranie, i dodatkowo adresuje wszystkie znaki spoza ascii, a nie konkretny znak.

Author: Community, 2013-11-19

6 answers

Twoje ''.join() wyrażenie to filtrowanie , Usuwanie czegokolwiek innego niż ASCII; zamiast tego możesz użyć wyrażenia warunkowego:

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

To obsługuje znaki jeden po drugim i nadal używa jednego spacji na znak zastąpiony.

Twoje Wyrażenie regularne powinno zastąpić kolejne znaki spoza ASCII spacją:

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

Zwróć uwagę na + tam.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-19 18:11:35

Dla Ciebie najbardziej podobna reprezentacja oryginalnego ciągu polecam moduł unidecode :

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

Następnie możesz użyć go w ciągu znaków:

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/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-22 17:58:00

Do przetwarzania znaków Użyj ciągów 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'

Ale pamiętaj, że nadal będziesz miał problem, jeśli twój ciąg znaków zawiera rozłożone znaki Unicode (na przykład oddzielny znak i łączące znaki akcentu):

>>> 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/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-19 21:26:15

Jeśli znak zastępczy może być '?'zamiast spacji proponuję 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(),
))

Wyniki:

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/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-03 11:12:33

A co z tym?

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/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-20 22:35:18

Jako natywne i efektywne podejście, nie musisz używać ord ani żadnej pętli nad znakami. Wystarczy zakodować za pomocą ascii i zignorować błędy.

Poniższe po prostu usunie znaki spoza ascii:

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

Teraz, jeśli chcesz zastąpić usunięte znaki, wykonaj następujące czynności:

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/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-23 14:39:32