测试Python字符串是否可打印

35 投票
10 回答
61553 浏览
提问于 2025-04-16 03:40

我有一段代码是从串口获取数据的,我想确保得到的内容真的是可以打印的字符串(也就是ASCII码,可能是UTF-8编码),在打印之前想确认一下。有没有什么函数可以做到这一点?我查了好几个地方,都没有找到看起来符合我需求的东西。(string模块里有一个printable,但我没有看到任何东西(在这里,或者在字符串方法中)可以检查一个字符串里的每个字符是否都在另一个字符串里。

我想要一个简单的函数,而不是自己动手写一个解决方案。

注意:控制字符对我来说是不可打印的。

10 个回答

6

这个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\\  ♀♂'
8

try/except 似乎是最好的方法:

def isprintable(s, codec='utf8'):
    try: s.decode(codec)
    except UnicodeDecodeError: return False
    else: return True

我不建议依赖 string.printable,因为它可能会把一些“不可打印”的控制字符当作不可打印的,而这些字符在终端控制中通常是可以“打印”的(比如在“上色”的 ANSI 转义序列中,如果你的终端支持 ANSI)。不过,这当然要看你具体想要检查什么了!-)

54

正如你所说,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)

撰写回答