python与编码,python编码,bytes和bytear
python与编码,python编码,bytes和bytear
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') >>> b b'xe4xb8xad' >>> 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'xe4xb8xad' >>> 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 == c2 False >>> len(c1), len(c2) (5, 4)
解决方法是通过unicodedata库中的normalize函数,该函数的第一个参数可以接受”NFC”,’NFD’,’NFKC’,’NFKD’四个参数中的一个。
NFC(Normalization Form Canonical Composition):以标准等价方式来分解,然后以标准等价重组之。若是singleton的话,重组结果有可能和分解前不同。尽可能的缩短整个字符串的长度,所以会把’eu0301’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 == c2 True >>> c4 = normalize('NFD',c2) >>> len(c4) 5 >>> c4 == c1 True
西方的键盘通常会键入尽可能短的字符串,也就是说和”NFC”的结果一致,但是通过”NFC”来操作一下再比较字符串是否相等比较安全。且W3C建议使用”NFC”的结果。
- 同样的一个字符在Unicode中有两个不同的编码。
该函数会把一个单一的Unicode字符转为另一个Unicode字符。
>>> o1 = '\u2126' >>> o2 = '\u03a9' >>> o1, o2 ('Ω', 'Ω') >>> o1 == o2 False >>> name(o1), name(o2) ('OHM SIGN', 'GREEK CAPITAL LETTER OMEGA') >>> o3 = normalize('NFC',o1) >>> name(o3) 'GREEK CAPITAL LETTER OMEGA' >>> o3 == o2 True
又比如
>>> 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, combining def 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 字符编码,python编码,未经作者许可,
- 聊一聊 Python 2 中的编码,python编码,未经作者许可,禁
- Python 字符编码实例,python编码实例,[Python]代码#c
- python获得字符的ASCII码,将ASCII数字转换为字符,pytho
- Python 处理各种编码的字符串,python编码字符串,Unicode
- 使用python对png图片文件做base64编码,,有时候我们需要使
- 两种python 判断网页编码的方法,python判断网页编码,这
- Python字符串的encode与decode研究心得——解决乱码问题,
- 获得图片的Base64编码,,python代码#!/u
- python读取中文文本文件的GBK和UTF-8编码问题,pythonutf-
评论关闭