用string.translate()将不可打印字符转换为点
我之前做过这个,结果发现这段代码看起来很丑,明明是个看似简单的任务。
我的目标是把任何不可打印的字符都转换成一个.(点)。在我看来,“可打印”的定义是排除掉一些特殊字符,比如换行符、制表符等等。这是为了打印像老版MS-DOS调试的“十六进制转储”格式……或者类似的东西(因为多余的空格会搞乱原本的转储布局)。
我知道可以用string.translate()
,但使用这个方法需要一个翻译表。所以我用string.maketrans()
来创建这个表。以下是我能想到的最佳方案:
filter = string.maketrans(
string.translate(string.maketrans('',''),
string.maketrans('',''),string.printable[:-5]),
'.'*len(string.translate(string.maketrans('',''),
string.maketrans('',''),string.printable[:-5])))
……这段代码看起来真是乱七八糟(不过确实能用)。
接下来你可以用类似这样的方式调用:
for each_line in sometext:
print string.translate(each_line, filter)
……这样就可以高兴地使用了。(只要你不去看底层实现)。
如果我把那段可怕的表达式拆分成几个单独的语句,代码会更易读:
ascii = string.maketrans('','') # The whole ASCII character set
nonprintable = string.translate(ascii, ascii, string.printable[:-5]) # Optional delchars argument
filter = string.maketrans(nonprintable, '.' * len(nonprintable))
这样做确实很诱人,主要是为了让代码更清晰。
不过,我一直在想,难道没有更优雅的方式来表达这个吗!
4 个回答
1
我觉得这个解决方案并不难看。它肯定比任何基于正则表达式的解决方案要高效得多。这里有一个稍微短一点的解决方案,不过只适用于python2.6:
nonprintable = string.maketrans('','').translate(None, string.printable[:-5])
filter = string.maketrans(nonprintable, '.' * len(nonprintable))
4
这里提到的“ascii”是个比较广泛的用法,但你大概明白什么意思了。
>>> import string
>>> ascii="".join(map(chr,range(256)))
>>> filter="".join(('.',x)[x in string.printable[:-5]] for x in ascii)
>>> ascii.translate(filter)
'................................ !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~.................................................................................................................................'
如果我在进行代码比赛的话,可能会用类似这样的写法:
filter='.'*32+"".join(map(chr,range(32,127)))+'.'*129
5
这里有另一种方法,使用列表推导式:
filter = ''.join([['.', chr(x)][chr(x) in string.printable[:-5]] for x in xrange(256)])