测试Python字符串是否可打印
我有一段代码是从串口获取数据的,我想确保得到的内容真的是可以打印的字符串(也就是ASCII码,可能是UTF-8编码),在打印之前想确认一下。有没有什么函数可以做到这一点?我查了好几个地方,都没有找到看起来符合我需求的东西。(string模块里有一个printable,但我没有看到任何东西(在这里,或者在字符串方法中)可以检查一个字符串里的每个字符是否都在另一个字符串里。
我想要一个简单的函数,而不是自己动手写一个解决方案。
注意:控制字符对我来说是不可打印的。
10 个回答
这个Python 3字符串里包含了各种特殊字符:
s = 'abcd\x65\x66 äüöë\xf1 \u00a0\u00a1\u00a2 漢字 \a\b\r\t\n\v\\ \231\x9a \u2640\u2642\uffff'
如果你试着在控制台显示它(或者使用repr
),它会很好地处理所有不可打印的字符:
>>> s
'abcdef äüöëñ \xa0¡¢ 漢字 \x07\x08\r\t\n\x0b\\ \x99\x9a ♀♂\uffff'
它足够聪明,可以识别比如水平制表符(\t
)是可打印的,但垂直制表符(\v
)则被认为是不可打印的(显示为\x0b
而不是\v
)。
其他所有不可打印的字符在repr
中也会显示为\xNN
或\uNNNN
。所以,我们可以用这个来做测试:
def is_printable(s):
return not any(repr(ch).startswith("'\\x") or repr(ch).startswith("'\\u") for ch in s)
可能还有一些边缘字符,比如不换行的空格(\xa0
)在这里被当作不可打印的。也许它不应该这样,但这些特殊字符可以硬编码处理。
附言:
你可以这样做来从字符串中提取出只有可打印的字符:
>>> ''.join(ch for ch in s if is_printable(ch))
'abcdef äüöëñ ¡¢ 漢字 \r\t\n\\ ♀♂'
try
/except
似乎是最好的方法:
def isprintable(s, codec='utf8'):
try: s.decode(codec)
except UnicodeDecodeError: return False
else: return True
我不建议依赖 string.printable
,因为它可能会把一些“不可打印”的控制字符当作不可打印的,而这些字符在终端控制中通常是可以“打印”的(比如在“上色”的 ANSI 转义序列中,如果你的终端支持 ANSI)。不过,这当然要看你具体想要检查什么了!-)
正如你所说,string
模块里有一个叫printable
的东西,所以我们只需要检查你的字符串里的所有字符是否都在printable
里面就可以了:
>>> hello = 'Hello World!'
>>> bell = chr(7)
>>> import string
>>> all(c in string.printable for c in hello)
True
>>> all(c in string.printable for c in bell)
False
你可以把两个字符串都转换成集合,这样集合里每个字符只会出现一次。然后检查你字符串生成的集合是否是可打印字符的一个子集,也就是说,是否所有字符都在可打印字符里面:
>>> printset = set(string.printable)
>>> helloset = set(hello)
>>> bellset = set(bell)
>>> helloset
set(['!', ' ', 'e', 'd', 'H', 'l', 'o', 'r', 'W'])
>>> helloset.issubset(printset)
True
>>> set(bell).issubset(printset)
False
所以,总结一下,你可能想要这样做:
import string
printset = set(string.printable)
isprintable = set(yourstring).issubset(printset)