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')
>>> b
b'\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)
<class '_io.TextIOWrapper'>
>>> 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的话,重组结果有可能和分解前不同。尽可能的缩短整个字符串的长度,所以会把'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 == 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的标准模块。
参考资料:
python与编码的更多相关文章
- python Unicode 编码解码
1 #将Unicode转换成普通的Python字符串:"编码(encode)" 2 unicodestring = u"Hello world" 3 utf8s ...
- python的编码问题
本文简单介绍了各种常用的字符编码的特点,并介绍了在python2.x中如何与编码问题作战 :) 请注意本文关于Python的内容仅适用于2.x,3.x中str和unicode有翻天覆地的变化,请查阅其 ...
- python 字符编码练习
通过下面的练习,加深对python字符编码的认识 # \x00 - \xff 256个字符 >>> a = range(256)>>> b = bytes(a) # ...
- Python 字符编码 zz
http://www.cnblogs.com/huxi/archive/2010/12/05/1897271.html 1. 字符编码简介 1.1. ASCII ASCII(American Stan ...
- python 之编码问题详解
前在一个项目中遇到用post提交一个xml,xml中含有中文,对于单独的py文件,使用urllib2.urlopen完全ok,但在django中使用就一直报编码错误,然后在网上看到这篇文章不错,决定m ...
- 19.python的编码问题
在正式说明之前,先给大家一个参考资料:戳这里 文章的内容参考了这篇资料,并加以总结,为了避免我总结的不够完善,或者说出现什么错误的地方,有疑问的地方大家可以看看上面那篇文章. 以下说明是针对于pyth ...
- Python字符编码详解
1. 字符编码简介 1.1. ASCII ASCII(American Standard Code for Information Interchange),是一种单字节的编码.计算机世界里一开始只有 ...
- python的编码
python的编码 1.概述 讲述编码,那么就要涉及到几个方面,包括系统中如何来显示字符,文件中如何来保存字符. 1.1 系统环境 在系统中显示字符,那么就必须要考虑到系统中使用的编码格式. 在lin ...
- 【转】Python字符编码详解
转自:http://www.cnblogs.com/huxi/archive/2010/12/05/1897271.html 1. 字符编码简介 1.1. ASCII ASCII(American S ...
随机推荐
- 利用JS_SDK实现QQ第三方登录
前言 现如今,第三方登录已成为大部分网站必备的一项基础技能,引入时髦的第三方登录不仅能帮你吸引更多的用户,也让你的网站可以充分利用其他大型网站的用户资源.本次教程将让你的网站最快捷便利地引入QQ登录. ...
- PHP之数组遍历
数组在PHP中是一个非常强大的武器,用起来方便.容易,由于使用起来异常灵活,用它就可以实现数据结构中的链表.栈.队列.堆以及所谓的字典.集合等,也可以转换成XML格式. 1.使用for for语句遍历 ...
- Logcat中报内存泄漏MemoryLeak的一次分析
有时候运行APP的时候Logcat中会报错,提示资源没有释放,Memory leak, 于是打开Android Studio在Android Monitor工具栏点开,有Logcat和Monitors ...
- dll不同的调用方式
LoadLibrary 一般是动态加载DLL时(你并不需要对应的头文件,和LIB) #pragma comment 一般是静态加载DLL时(对应的头文件.DLL,和LIB缺一不可,并且生产的EXE没有 ...
- java web 优化札记
1.效果最明显最简单最省事的优化是SSD,一般优化效率3倍起,(未必对,但是说明很多瓶颈问题都是存储问题) 2.垂直扩容省了开发时间,短期来看是最快的,缺点是会消耗更多的资源,而且有瓶颈,另外如果应用 ...
- HW--字符串加解密
package t0817; import java.util.Scanner; public class StringEncrypt { public static void main(String ...
- XMPP即时通讯(代码实现)
1.配置XMPP(XMPPConfig.m) 2.配置XMPPFramework框架 3.创建单例类(XMPPManager.h/XMPPManager.m)管理器 XMPPManager.m: #i ...
- C#5.0之后推荐使用TPL(Task Parallel Libray 任务并行库) 和PLINQ(Parallel LINQ, 并行Linq). 其次是TAP(Task-based Asynchronous Pattern, 基于任务的异步模式)
学习书籍: <C#本质论> 1--C#5.0之后推荐使用TPL(Task Parallel Libray 任务并行库) 和PLINQ(Parallel LINQ, 并行Linq). 其次是 ...
- VIM 拼写/spell check
VIM 拼写检查/spell check 一.Hunspell科普 Hunspell 作为一个拼写检查的工具,已经用在了许多开源的以及商业软件中.包括Google Chrome, Libreoffic ...
- ESP8266开发课堂之 - 建立一个新项目
项目架构 ESP8266项目开发并非使用IDE自动管理工程文件,而是使用了诸多第三方程序如Python,以及使用了Makefile管理依赖与控制编译,所以项目的创建与日常维护较为复杂,本篇将详述创建一 ...