如何使用Python删除非ASCII字符但保留句点和空格?


100

我正在使用.txt文件。我希望文件中的文本字符串不包含非ASCII字符。但是,我想留空格和句点。目前,我也正在剥离它们。这是代码:

def onlyascii(char):
    if ord(char) < 48 or ord(char) > 127: return ''
    else: return char

def get_my_string(file_path):
    f=open(file_path,'r')
    data=f.read()
    f.close()
    filtered_data=filter(onlyascii, data)
    filtered_data = filtered_data.lower()
    return filtered_data

我应该如何修改onlyascii()以保留空格和句点?我想这并不太复杂,但我无法弄清楚。


(真诚地)感谢约翰的澄清。我知道空格和句点是ASCII字符。但是,在尝试仅删除非ASCII字符时,我无意中删除了它们。我明白了我的问题可能是如何暗示的。

@PoliticalEconomist:您的问题仍然很不明确。看我的答案。
约翰·马钦

Answers:


187

您可以使用string.printable过滤字符串中所有不可打印的字符,如下所示:

>>> s = "some\x00string. with\x15 funny characters"
>>> import string
>>> printable = set(string.printable)
>>> filter(lambda x: x in printable, s)
'somestring. with funny characters'

我机器上的string.printable包含:

0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c

编辑:在Python 3上,筛选器将返回可迭代。返回字符串的正确方法是:

''.join(filter(lambda x: x in printable, s))

2
序号48以下的那些可打印字符是怎么回事?
joaquin 2011年

38
使用的唯一问题filter是它返回一个可迭代的。如果您需要返回一个字符串(就像我所做的那样(因为在执行列表压缩时需要此字符串)),请执行以下操作:''.join(filter(lambda x: x in string.printable, s)
cjbarth 2014年

5
@cjbarth-评论是特定于python 3的,但是非常有用。谢谢!
2015年

7
为什么不使用正则表达式: re.sub(r'[^\x00-\x7f]',r'', your-non-ascii-string)。看到这个线程stackoverflow.com/a/20079244/658497
Noam Manos

1
@NoamManos这对我来说要快4-5倍,那是join ... filter ... lambda解决方案,谢谢。
artfulrobot

95

更改为其他编解码器的简单方法是使用encode()或decode()。在您的情况下,您想转换为ASCII并忽略所有不支持的符号。例如,瑞典字母å不是ASCII字符:

    >>>s = u'Good bye in Swedish is Hej d\xe5'
    >>>s = s.encode('ascii',errors='ignore')
    >>>print s
    Good bye in Swedish is Hej d

编辑:

Python3:str->字节-> str

>>>"Hej då".encode("ascii", errors="ignore").decode()
'hej d'

Python2:unicode-> str-> unicode

>>> u"hej då".encode("ascii", errors="ignore").decode()
u'hej d'

Python2:str-> unicode-> str(以相反的顺序解码和编码)

>>> "hej d\xe5".decode("ascii", errors="ignore").encode()
'hej d'

16
我明白了UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 27
Xodarap777

2
通过复制粘贴将实际的unicode字符放入字符串时,出现了该错误。当您将字符串指定为u'thestring'时,编码可以正常工作。
Ben Liyanage 2015年

2
仅在Py3上有效,但是很优雅。
凌晨

7
对于那些遇到与@ Xodarap777相同的错误的用户:您应该首先.decode()字符串,然后再进行编码。例如s.decode('utf-8').encode('ascii', errors='ignore')
Spc_555 '17


6

您的问题不明确;前两个句子加在一起表示您认为空格和“句点”是非ASCII字符。这是不正确的。等于ord(char)<= 127的所有字符都是ASCII字符。例如,您的函数不包括这些字符!“#$%&\'()* +,-。/,但包括其他几个字符,例如[] {}。

请退后一步,三思而后行,然后编辑您的问题以告诉我们您要做什么,而无需提及ASCII单词,以及为什么您认为ord(char)> = 128这样的chars是可忽略的。另外:哪个版本的Python?输入数据的编码是什么?

请注意,您的代码将整个输入文件读取为单个字符串,并且您对另一个答案的注释(“最佳解决方案”)意味着您无需关心数据中的换行符。如果您的文件包含这样的两行:

this is line 1
this is line 2

结果将是'this is line 1this is line 2'……您真正想要的是什么?

更好的解决方案包括:

  1. 过滤器功能比一个更好的名字 onlyascii
  2. 认识到如果要保留参数,则过滤器功能仅需要返回真实值:

    def filter_func(char):
        return char == '\n' or 32 <= ord(char) <= 126
    # and later:
    filtered_data = filter(filter_func, data).lower()

这个答案对我们中那些要问类似OP的人很有帮助,而您提出的答案很有帮助。但是,我确实感到奇怪,在您解释该问题时,没有一种更有效的解决方案(我经常遇到)-一个字符接一个字符,这在一个很大的文件中花费很长时间。
Xodarap777

5

您可以使用以下代码删除非英语字母:

import re
str = "123456790 ABC#%? .(朱惠英)"
result = re.sub(r'[^\x00-\x7f]',r'', str)
print(result)

这将返回

123456790 ABC#%?。()


1

如果您需要可打印的ASCII字符,则可能应将代码更正为:

if ord(char) < 32 or ord(char) > 126: return ''

等同于string.printable(@jterrace的答案),除了没有返回和制表符('\ t','\ n','\ x0b','\ x0c'和'\ r'),但不对应您问题的范围


1
稍微简单一点:lambda x:32 <= ord(x)<= 126
jterrace 2011年

这与string.printable不同,因为它省略了string.whitespace,尽管这可能是OP想要的,但它取决于\ n和\ t之类的东西。
jterrace 2011年

@jterrace右边,包括空格(ord 32),但没有返回和制表符
joaquin 2011年

是的,只是评论“这等效于string.printable”,但不是正确的
jterrace 2011年

我编辑了答案,谢谢!如果您没有仔细阅读OP的问题,则会产生误导。
joaquin 2011年

1

我强烈推荐使用Fluent Python(Ramalho)。列出受第二章启发的单线班级理解:

onlyascii = ''.join([s for s in data if ord(s) < 127])
onlymatch = ''.join([s for s in data if s in
              'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'])

这将不允许使用标准的ASCII符号,例如项目符号,度数符号,版权符号,日元符号等。而且,您的第一个示例包括不可打印的符号,例如BELL,这是不希望的。
SherylHohman
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.