用单个空格替换非ASCII字符

时间:2013-11-19 18:09:03

标签: python unicode encoding ascii

我需要用空格替换所有非ASCII(\ x00- \ x7F)字符。我很惊讶这在Python中并不容易,除非我遗漏了一些东西。以下函数只删除所有非ASCII字符:

def remove_non_ascii_1(text):

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

这个用字符代码点中的字节数替换非ASCII字符和空格量(即字符被3个空格替换):

def remove_non_ascii_2(text):

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

如何用一个空格替换所有非ASCII字符?

Of the myriad of similar SO questionsnone address { {3}} character replacement as opposed tostripping还解决了非特定字符的所有非ascii字符。

9 个答案:

答案 0 :(得分:207)

您的''.join()表达式过滤,删除任何非ASCII码;你可以使用条件表达式:

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

这将逐个处理字符,并且每个字符替换时仍会使用一个空格。

您的正则表达式应该只用空格替换连续的非ASCII字符:

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

请注意那里的+

答案 1 :(得分:44)

对于您来说,我建议使用the unidecode module

来获得原始字符串最相似的表示形式
from unidecode import unidecode
def remove_non_ascii(text):
    return unidecode(unicode(text, encoding = "utf-8"))

然后你可以在字符串中使用它:

remove_non_ascii("Ceñía")
Cenia

答案 2 :(得分:19)

对于字符处理,请使用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'

但请注意,如果您的字符串包含已分解的Unicode字符(例如,单独的字符和组合重音符号),您仍会遇到问题:

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

答案 3 :(得分:7)

如果替换字符可以是'?'而不是空格,那么我建议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(),
))

结果:

0.7208260721400134
0.009975979187503592

答案 4 :(得分:6)

这个怎么样?

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

答案 5 :(得分:2)

作为一种原生且高效的方法,您不需要对字符使用ord或任何循环。只需使用ascii进行编码并忽略错误。

以下将删除非ascii字符:

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

现在,如果您想要替换已删除的字符,请执行以下操作:

final_string = new_string + b' ' * (len(old_string) - len(new_string))

答案 6 :(得分:1)

当我们使用 ascii() 时,它会转义非 ascii 字符,并且不会正确更改 ascii 字符。所以我的主要想法是,它不会改变 ASCII 字符,所以我遍历字符串并检查字符是否改变。如果它改变了,那么用替换器替换它,你给什么。
例如:' '(一个空格)或 '?' (带问号)。

def remove(x, replacer):

     for i in x:
        if f"'{i}'" == ascii(i):
            pass
        else:
            x=x.replace(i,replacer)
     return x
remove('hái',' ')

结果:“h i”(中间有一个空格)。

语法:remove(str,non_ascii_replacer)
str = 在这里,您将提供要使用的字符串。
non_ascii_replacer = 在这里,您将提供要替换所有非 ASCII 字符的替换器。

答案 7 :(得分:0)

我的问题是我的字符串包含了像 België 的 Belgià 和 € 符号的 &#x20AC 之类的东西。我不想用空格替换它们。但是使用正确的符号本身。

我的解决方案是 string.encode('Latin1').decode('utf-8')

答案 8 :(得分:-1)

可能会提出其他问题,但我正在提供@Alvero答案的版本(使用unidecode)。我想在字符串上执行“常规”删除,即在字符串的开头和结尾输入空白字符,然后仅将其他空白字符替换为“常规”空格,即

"Ceñíaㅤmañanaㅤㅤㅤㅤ"

"Ceñía mañana"

def safely_stripped(s: str):
    return ' '.join(
        stripped for stripped in
        (bit.strip() for bit in
         ''.join((c if unidecode(c) else ' ') for c in s).strip().split())
        if stripped)

我们首先将所有非unicode空格替换为常规空格(然后重新加入)

''.join((c if unidecode(c) else ' ') for c in s)

然后我们使用python的正常拆分方法再次拆分,并剥离每个“位”,

(bit.strip() for bit in s.split())

最后再次将它们重新加入,但前提是该字符串通过了if测试,

' '.join(stripped for stripped in s if stripped)

并且,safely_stripped('ㅤㅤㅤㅤCeñíaㅤmañanaㅤㅤㅤㅤ')正确地返回'Ceñía mañana'