Python食谱-1.11.确定字符串为文本还是二进制编码
| 原文作者: | Andrew Dalke |
|---|---|
| 中文编译: | Tony (digitalsatori) |
问题
Python的字符串对象既可以保存文本也可以保存任意字节码。如何确定某个字符串保存了何种内容?
解决办法
我可以借鉴Perl的试探法来解决该问题。如果一个字符串包含任何空字符,或者如果其超过30%的字符拥有高位码(大于126的编码)或一些特殊控制字符,那么我们确定此字符串包含二进制编码。
from __future__ import division # ensure / does NOT truncate
import string
text_characters = "".join(map(chr, range(32, 127))) + "\n\r\t\b"
_null_trans = string.maketrans("", "")
def istext(s, text_characters=text_characters, threshold=0.30):
# if s contains any null, it's not text:
if "\0" in s:
return False
# an "empty" string is "text" (arbitrary but reasonable choice):
if not s:
return True
# Get the substring of s made up of non-text characters
t = s.translate(_null_trans, text_characters)
# s is 'text' if less than 30% of its characters are non-text ones:
return len(t)/len(s) <= threshold
讨论
你可以很容易的对istext函数作微调,比如传递给他一个指定的值(默认的值为0.30),或者改变text_characters(其值用以说明哪些字符被认作文本,默认的值为所有普通ASCII字符和四个常见的控制字符)。比如我们希望文本字符中包括ISO-8859-1编码的意大利文,我们可以将"àèéìÃ2Ã1"意大利重音符号加入到text_characters。
在大多数情况下,我们需要对文件检测是文本还是字节码。我们可以用istext函数检测文件的开始一段:
def istextfile(filename, blocksize=512, **kwds):
return istext(open(filename).read(blocksize), **kwds)
对于低于3.0版本的Python, 使用除号操作符 / 对两个整数相除,返回的值为去除小数位的整数值。在以上代码中我们使用了:
from future import division
使我们能使用3.0版本中关于除号操作符的不同特性,即两整数相除返回值可以是浮点数。














请问如果包括中文的文本,用这个检测还灵不灵?
简单的回答是用这个检测不灵。
如果仔细看这个函数的构成就能了解作者对“文本“的定义。
事实上要区分文本还是二进制编码,其本身就是一个伪命题,因为python 2.x中字符串(string)都是二进制编码的(binary code),所谓不同的文本只是以不同编码规则(encoding)所生成二进制码而已。
作者在这里只是要区分ASCII码编码从32-127的字符和一些控制字符。