python与编码

python中的文字对象

python 3.x中处理文字的对象有str, bytes, bytearray。

bytes和bytearray可以使用除了用作格式化的方法(format, format_map)以及几个特殊的基于unicode的方法(casefold, isdecimal, isidentifier, isnumeric, isprintable, encode)以外几乎所有str的方法。

bytes有一个类方法,可以通过序列来构建字符串,而这个方法不可以用在str上。

>>> b = bytes.fromhex(‘e4 b8 ad’)>>> bb’\xe4\xb8\xad’>>> b.decode(‘utf-8’)’中’>>> str(b)”b’\\xe4\\xb8\\xad'”

unicode和字符转换

采用chr可以把一个unicode的code point转换为字符,通过ord可以进行反向操作。

>>> ord(‘a’)65>>> ord(‘中’)20013>>> chr(65)’a’>>> chr(20013)’中’

len函数计算的是字符数,不是字节数

>>> len(‘中’)1>>> ‘中’.encode(‘utf-8’)b’\xe4\xb8\xad’>>> len(‘中’.encode(‘utf-8’)) #计算的是bytes对象的长度,包含3个整数字符3

python与编码

python内部处理编码的方式

在python接受我们的输入时,总是会先转为unicode。而且这个过程越早越好。然后python的处理总是对unicode进行的,在这个过程中,一定不要进行编码转换的工作。在python向我们返回结果时,总是会从unicode转为我们需要的编码。而且这个过程越晚越好。

python源码的编码方式

python默认使用utf-8编码。如果想使用一种不同的编码方式来保存python代码,我们可以在每个文件的第一行或者第二行(如果第一行被hash-bang命令占用了)放置编码声明(encoding declaration)# ‐*‐ coding: windows‐1252 ‐*‐

python中使用的编码

c:\users\jl>chcp #查找操作系统使用的编码active code page: 936>>> import sys, locale>>> locale.getpreferredencoding() #这个是最重要的’cp936’>>> my_file = open(‘cafe.txt’,’r’)>>> type(my_file)>>> my_file.encoding #文件对象默认使用locale.getpreferreddecoding()的值’cp936’>>> sys.stdout.isatty(), sys.stdin.isatty(), sys.stderr.isatty() #output是否是控制台console(true, true, true)>>> sys.stdout.encoding, sys.stdin.encoding, sys.stderr.encoding #sys的标准控制流如果被重定向,或者定向到文件,那么编码将使用环境变量pythonioencoding的值、控制台console的编码、或者locale.getpreferredencoding()的编码,优先级依次减弱。(‘cp936’, ‘cp936’, ‘cp936′)>>> sys.getdefaultencoding() #如果python需要把二进制数据转为字符对象,那么在缺省情况下使用该值。’utf-8’>>> sys.getfilesystemencoding() #python用来编码或者解码文件名(不是文件内容)的时候,默认使用该编码。’mbcs’

以上是在windows中的测试结果,如果在gnu/linux或者osx中,那么所有的结果都是utf-8.关于mbcs和utf-8的区别,可以参考http://stackoverflow.com/questions/3298569/difference-between-mbcs-and-utf-8-on-windows

文件读写的编码

>>> pen(‘cafe.txt’,’w’,encoding=’utf-8′).write(‘café’)4>>> fp = open(‘cafe.txt’,’r’)>>> fp.read()’caf茅’>>> fp.encoding’cp936’>>> open(‘cafe.txt’,’r’, encoding = ‘cp936’).read()’caf茅’>>> open(‘cafe.txt’,’r’, encoding = ‘latin1’).read()’café’>>> fp = open(‘cafe.txt’,’r’, encoding = ‘utf-8′)>>> fp.encoding’utf-8’

从上面的例子可以看出,无论什么时候都不要使用默认的编码,因为在不同的机器上运行的时候会出现意想不到的问题。

python如何处理来自unicode的麻烦

python总是通过code point来比较字符串的大小,或者是否相等的。

unicode中重音符号有两种表示方法,用一个字节表示,或者用基字母加上重音符号表示,在unicode中他们是相等的,但是在python中由于通过code point来比较大小,所以就不相等了。

>>> c1 = ‘cafe\u0301’>>> c2 = ‘café’>>> c1 == c2false>>> len(c1), len(c2)(5, 4)

解决方法是通过unicodedata库中的normalize函数,该函数的第一个参数可以接受”nfc”,’nfd’,’nfkc’,’nfkd’四个参数中的一个。nfc(normalization form canonical composition):以标准等价方式来分解,然后以标准等价重组之。若是singleton的话,重组结果有可能和分解前不同。尽可能的缩短整个字符串的长度,所以会把’e\u0301’2个字节压缩到一个字节’é’。nfd(normalization form canonical decomposition):以标准等价方式来分解nfkd(normalization form compatibility decomposition):以相容等价方式来分解nfkc(normalization form compatibility composition):以相容等价方式来分解,然后以标准等价重组之。nfkc和nfkd可能会引起数据损失。

from unicodedata import normalize>>> c3 = normalize(‘nfc’,c1) #把c1往字符串长度缩短的方向操作>>> len(c3)4>>> c3 == c2true>>> c4 = normalize(‘nfd’,c2)>>> len(c4)5>>> c4 == c1true

西方的键盘通常会键入尽可能短的字符串,也就是说和”nfc”的结果一致,但是通过”nfc”来操作一下再比较字符串是否相等比较安全。且w3c建议使用”nfc”的结果。

同样的一个字符在unicode中有两个不同的编码。该函数会把一个单一的unicode字符转为另一个unicode字符。

>>> o1 = ‘\u2126’>>> o2 = ‘\u03a9’>>> o1, o2(‘Ω’, ‘Ω’)>>> o1 == o2false>>> name(o1), name(o2)(‘ohm sign’, ‘greek capital letter omega’)>>> o3 = normalize(‘nfc’,o1)>>> name(o3)’greek capital letter omega’>>> o3 == o2true

又比如

>>> u1 = ‘\u00b5’>>> u2 = ‘\u03bc’>>> u1,u2(‘µ’, ‘μ’)>>> name(u1), name(u2)(‘micro sign’, ‘greek small letter mu’)>>> u3 = normalize(‘nfkd’,u1)>>> name(u3)’greek small letter mu’

再一个例子

>>> h1 = ‘\u00bd’>>> h2 = normalize(‘nfkc’,h1)>>> h1, h2(‘½’, ‘1⁄2’)>>> len(h1), len(h2)(1, 3)

有时候我们希望使用不区分大小写的形式进行比较使用方法str.casefold(),该方法会把大写字母转换为小写进行比较,比如’a’会转为’a’,’micro sign’的’µ’会转换为’greek small letter mu’的’µ’在绝大部分(98.9%)情况下str.casefold()和str.lower()的结果一致。

文字排序由于不同的语言规则,如果单纯按照python的比较code point的方式进行,那么会出现很多不是用户期望的结果。通常采用locale.strxfrm进行排序。

>>> import locale>>> locale.setlocale(locale.lc_collate,’pt_br.utf-8′)’pt_br.utf-8’>>> sort_result = sorted(intial, key = locale.strxfrm)

编码解码错误

如果是python源码中出现了解码错误,那么会产生syntaxerror异常。其他情况下,如果发现编码解码错误,那么会产生unicodeencodeerror, unicodedecodeerror异常。

几个摘自fluent python中的有用方法

from unicodedata import normalize, combiningdef nfc_equal(s1, s2): ”’return true if string s1 is eual to string s2 after normalization under “nfc” ”’ return normalize(“nfc”,s1) == normalize(“nfc”,s2)def fold_equal(s1, s2): ”’return true if string s1 is eual to string s2 after normalization under “nfc” and casefold()”’ return normalize(‘nfc’,s1).casefold() == normalize(‘nfc’,s2).casefold()def shave_marks(txt): ”’remove all diacritic marks basically it only need to change latin text to pure ascii, but this func will change greek letters also below shave_latin_marks func is more precise”’ normal_txt = normalize(‘nfd’,txt) shaved = ”.join(c for c in normal_txt if not combining(c)) return normalize(‘nfc’,shaved)def shave_latin_marks(txt): ”’remove all diacritic marks from latin base characters”’ normal_txt = normalize(‘nfd’,txt) keeping = [] latin_base=false for c in normal_txt: if combining(c) and latin_base: continue #ingore diacritic marks on latin base char keeping.append(c) #if it’s not combining char, it should be a new base char if not combining(c): latin_base = c in string.ascii_letters

编码探嗅chardet

这是python的标准模块。

参考资料:

http://blog.csdn.net/tcdddd/article/details/8191464

以上就是python与编码的内容,更多相关文章请关注php中文网(www.php1.cn)!

Posted in 未分类

发表评论