Replace non-ASCII characters with a single space
我需要用空格替换所有非ASCII(x00-x7f)字符。我很惊讶,这在Python中并不容易实现,除非我遗漏了一些东西。以下函数只删除所有非ASCII字符:
1 2 3 | def remove_non_ascii_1(text): return ''.join(i for i in text if ord(i)<128) |
该字符根据字符码位中的字节数(即用3个空格替换
1 2 3 | def remove_non_ascii_2(text): return re.sub(r'[^\x00-\x7F]',' ', text) |
如何用一个空格替换所有非ASCII字符?
在无数类似的这样的问题中,无地址字符替换(而不是剥离),并且另外地址所有非ASCII字符而不是特定字符。
您的
1 | return ''.join([i if ord(i) < 128 else ' ' for i in text]) |
它一个接一个地处理字符,并且每替换一个字符仍然使用一个空格。
正则表达式只应将连续的非ASCII字符替换为空格:
1 | re.sub(r'[^\x00-\x7F]+',' ', text) |
注意那里的
对于最相似的原始字符串表示,我建议使用unidecode模块:
1 2 3 | from unidecode import unidecode def remove_non_ascii(text): return unidecode(unicode(text, encoding ="utf-8")) |
然后您可以在字符串中使用它:
1 2 | remove_non_ascii("Ce?ía") Cenia |
对于字符处理,请使用Unicode字符串:
1 2 3 4 5 6 7 8 | 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字符(例如,分隔字符和组合重音标记),则仍然存在问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 | >>> s = 'ma?ana' >>> len(s) 6 >>> import unicodedata as ud >>> n=ud.normalize('NFD',s) >>> n 'man?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' |
如果替换字符可以是'?'我建议用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | """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(), )) |
结果:
1 2 | 0.7208260721400134 0.009975979187503592 |
这个怎么样?
1 2 3 4 5 6 7 8 | 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 |
作为一种本机且高效的方法,您不需要使用
以下仅删除非ASCII字符:
1 | new_string = old_string.encode('ascii',errors='ignore') |
现在,如果要替换已删除的字符,请执行以下操作:
1 | final_string = new_string + b' ' * (len(old_string) - len(new_string)) |
有可能是另一个问题,但我提供了@alvero的答案(使用unidecode)。我想在我的字符串上做一个"常规"条带,也就是说,我的字符串的开头和结尾都是空白字符,然后用一个"常规"空格替换其他的空白字符,也就是说。
1 | "Ce?ía?ma?ana????" |
到
1 | "Ce?ía ma?ana" |
,
1 2 3 4 5 6 | 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空间(然后重新连接它)。
1 | ''.join((c if unidecode(c) else ' ') for c in s) |
然后我们用python的正常拆分再次拆分,并去掉每个"位",
1 | (bit.strip() for bit in s.split()) |
最后再把它们连接起来,但前提是字符串通过了
1 | ' '.join(stripped for stripped in s if stripped) |
据此,