python与编码

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體: 小  |  中  |  大  |  超大  

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的标准模块。

参考资料:

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

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航