将非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字符?

无数 类似的 所以 问题没有一个 地址 字符 0 1 2 3 4, 5额外地址所有非ascii字符而不是特定字符。

271646 次浏览

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

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

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

正则表达式应该用空格替换连续非ascii字符:

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

注意这里的+

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

为了获得与原始字符串最相似的表示,我推荐unidecode模块:

# python 2.x:
from unidecode import unidecode
def remove_non_ascii(text):
return unidecode(unicode(text, encoding = "utf-8"))

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

remove_non_ascii("Ceñía")
Cenia

这个怎么样?

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

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

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

下面只会删除非ascii字符:

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

现在,如果你想替换被删除的字符,只需执行以下操作:

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

可能是为了一个不同的问题,但我提供了@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'

当我们使用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)
这里你将给出你想要使用的字符串。
non_ascii_replacer =在这里你将给出你想要替换所有非ASCII字符的替换器

我的问题是我的字符串包含诸如BelgiÃ的België和&#x20AC的€符号。我不想把它们换成空格。但要有正确的符号。

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

将所有非ascii (\x00-\x7F)字符替换为空格:

''.join(map(lambda x: x if ord(x) in range(0, 128) else ' ', text))

要替换所有可见字符,请尝试以下操作:

import string


''.join(map(lambda x: x if x in string.printable and x not in string.whitespace else ' ', text))

这将给出相同的结果:

''.join(map(lambda x: x if ord(x) in range(32, 128) else ' ', text))

使用乐烧(以前称为Perl_6)进行预处理

~$ raku -pe 's:g/ <:!ASCII>+ / /;' file

样例输入:

Peace be upon you
السلام عليكم
שלום עליכם
Paz sobre vosotros

样例输出:

Peace be upon you




Paz sobre vosotros

注意,你可以使用下面的代码获得大量的匹配信息:

~$ raku -ne 'say s:g/ <:!ASCII>+ / /.raku;' file
$( )
$(Match.new(:orig("السلام عليكم"), :from(0), :pos(6)), Match.new(:orig("السلام عليكم"), :from(7), :pos(12)))
$(Match.new(:orig("שלום עליכם"), :from(0), :pos(4)), Match.new(:orig("שלום עליכם"), :from(5), :pos(10)))
$( )
$( )

或者更简单地说,你可以想象一下替换的空格:

~$ raku -ne 'say S:g/ <:!ASCII>+ / /.raku;' file
"Peace be upon you"
"   "
"   "
"Paz sobre vosotros"
""
< p > https://docs.raku.org/language/regexes#Unicode_properties
https://www.codesections.com/blog/raku-unicode/
https://raku.org < / p >
def filterSpecialChars(strInput):
result = []
for character in strInput:
ordVal = ord(character)
if ordVal < 0 or ordVal > 127:
result.append(' ')
else:
result.append(character)
return ''.join(result)

像这样叫它:

result = filterSpecialChars('Ceñía mañana')
print(result)