Python建议:考虑兼容性,尽可能使用Unicode
2016-12-06 15:52
836 查看
Python内建字符串有两种类型:str和Unicode。它们的共同祖先是basestring。Unicode是Python2.0中引入的一种新的数据类型。所有Unicode字符串都是Unicode类的实例。
为了统一不同编码,Unicode产生了,它也被称谓万国码。Unicode编码系统可以分成编码方式和实现方式两个层次。在编码方式上,分为UCS-2和UCS-4两种方式。UCS-2使用两个字节编码。而UCS-4使用4个字节编码。目前实际应用的统一码对应于UCS-2使用16bit的编码空间。一个字符的Unicode编码是确定的,但实际传输过程,由于系统平台不同以及处于节约空间的目的,实现方式有所差异。Unicode的实现方式被称为UTF(Unicode Transformation Format),包括UTF-7,UTF-8,UTF-16,UTF-32,其中最常用的为UTF-8。特点是对不同范围的字符使用不同长度的编码方式。其中0x00到0x7F的字符的UTF-8编码与ASCII编码完全相同(因此以ASCII来输出UTF-8时,英文输出没问题,如下表所示,读取以0开头的字节都等价于ASCII编码)。
注意:ASICII 美国信息交换标准编码(American Standard Code for Information Interchange),是用于表示字符的8位编码(7位再加上校验位)。正确的拼法应该是ASCII,而不是ASICII。这是某些人笔误的结果。世界上没有ASICII这种编码,只有ASCII。
Unicode和UTF-8编码的互转方式
Unicode经过多年发展,已经成为业界标准。
Python中文处理会遇到以下几个问题:
此时输出结果如下所示:
对于第一句输出,由于文本是UTF-8编码,而控制台使用的编码为GBK编码,故此时输出乱码。
对于第二句输出,由于对文本使用了UTF-8解码,Python在调用print函数时自动进行编码(和环境变量有关)为GBK后输出。使用print(locale.getdefaultlocale())可以查看当前控制台的编码方式。CP936几乎就是GBK,IBM在发明Code Page的时候将GBK放在第936页,所以叫CP936。但其实两者稍微有区别,这里不做展开。
cp936和GBK还是有些差别的。淘宝的技术团队发现他们的MYSQL数据库在GBK字符集下无法插入欧元符号。然后就打了一个补丁。 其实也不能说MYSQL的代码有问题,GBK中的确没有0x80这个字符。但是cp936中有。可是cp936又不是标准,因为即便是微软内部,不同的windows版本的CP936范围都不一样。
编码的问题害死很多人啊http://rdc.taobao.com/blog/cs/?p=679
以下是常见的编码参数:
解码和编码时可以选择码和出错时的处理方式,错误处理方式一般有三种:
1) strict,出错时抛出UnicodeDecodeError异常。
2) ignore,出错时忽略不可转换字符。
3) replace,出错时使用?代替不可转换字符。
以下是解码和编码函数。
对于A/B两种编码方式,两者转换的示意图如下所示:
BOM
实际上UTF-8编码分为带BOM和不带BOM两种:
如果文本是UTF-8带BOM的话,会有其他乱码出现,或者有报错信息。
使用codecs模块可以很方便地处理带BOM的UTF-8文件。
以下是关于BOM的相关知识:
Unicode存储有字节序问题,例如“汉”一字,的Unicode编码0x6C49。存储时,6C写在前面,则称谓Big Endian,将49写在前面则称为Little Endian。UTF-8一般不需要BOM来表标明字节序,但还是可以用BOM标明。字符Zero Width No-Break Space的UTF-8编码是ef bb bf。所以如果接受者接收到ef bb bf开头的字节流,就知道是UTF-8编码吧。
由于Python默认编码为ASCII编码,代码中包含中文将会报错。如果需要使用中文,需要指定编码方式。
编码方式的声明有三种格式,可以用正则表达式来总结这三种编码方式 coding[:=]\s*([-\w.]+),符合这个正则表达式的都是有效的,比如
但下面是无效的,因为:和=前面多了空格。
以下是三种可选的声明方式
加上编码声明后,示例二可以正常输出。
解决以上问题,有三种思路。
1)使用正确的解码方式(以python文本的编码方式作为解码)。
2)对Unicode字符串进行编码
3)Python2.6之后,可以通过from future import unicode_literals自动转义str字符串为Unicode字符串。
# coding:utf-8 strUnicode = u'unicode 字符串' # 前面加u表示Unicode raw = '%r' % strUnicode # 原生输出,默认print打印的时候会自动进行编码。 print(raw) print("让print函数自动进行编码:") print(strUnicode) print("打印字符串的类:") print(type(strUnicode)) print("打印字符串的类的父类:") print(type(strUnicode).__base__) print("打印字符串的类的父类的父类:") print(type(strUnicode).__base__.__base__) print("打印字符串的类的父类的父类的父类:") print(type(strUnicode).__base__.__base__.__base__)
为了统一不同编码,Unicode产生了,它也被称谓万国码。Unicode编码系统可以分成编码方式和实现方式两个层次。在编码方式上,分为UCS-2和UCS-4两种方式。UCS-2使用两个字节编码。而UCS-4使用4个字节编码。目前实际应用的统一码对应于UCS-2使用16bit的编码空间。一个字符的Unicode编码是确定的,但实际传输过程,由于系统平台不同以及处于节约空间的目的,实现方式有所差异。Unicode的实现方式被称为UTF(Unicode Transformation Format),包括UTF-7,UTF-8,UTF-16,UTF-32,其中最常用的为UTF-8。特点是对不同范围的字符使用不同长度的编码方式。其中0x00到0x7F的字符的UTF-8编码与ASCII编码完全相同(因此以ASCII来输出UTF-8时,英文输出没问题,如下表所示,读取以0开头的字节都等价于ASCII编码)。
注意:ASICII 美国信息交换标准编码(American Standard Code for Information Interchange),是用于表示字符的8位编码(7位再加上校验位)。正确的拼法应该是ASCII,而不是ASICII。这是某些人笔误的结果。世界上没有ASICII这种编码,只有ASCII。
Unicode和UTF-8编码的互转方式
Unicode编码(十六进制) | UTF-8字节流(二进制) |
U-00000000 - U-0000007F | 0xxxxxxx |
U-00000080 - U-000007FF | 110xxxxx 10xxxxxx |
U-00000800 - U-0000FFFF | 1110xxxx 10xxxxxx 10xxxxxx |
U-00010000 - U-001FFFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
U-00200000 - U-03FFFFFF | 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx |
U-04000000 - U-7FFFFFFF | 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx |
Python中文处理会遇到以下几个问题:
例子1
在Windows控制台运行以下代码,文本使用UTF-8编码,文本test的内容如下所示:python 中文测试 python python 中文测试 python python 中文测试 python
代码如下所示: import locale filehandle = open(r'E:\test.txt', 'r') print(filehandle.readline()) print(filehandle.readline().decode('utf-8')) print("The locale is:") print(locale.getdefaultlocale()) print(filehandle.readline().decode('utf-8').encode('gbk')) filehandle.close()
此时输出结果如下所示:
对于第一句输出,由于文本是UTF-8编码,而控制台使用的编码为GBK编码,故此时输出乱码。
对于第二句输出,由于对文本使用了UTF-8解码,Python在调用print函数时自动进行编码(和环境变量有关)为GBK后输出。使用print(locale.getdefaultlocale())可以查看当前控制台的编码方式。CP936几乎就是GBK,IBM在发明Code Page的时候将GBK放在第936页,所以叫CP936。但其实两者稍微有区别,这里不做展开。
cp936和GBK还是有些差别的。淘宝的技术团队发现他们的MYSQL数据库在GBK字符集下无法插入欧元符号。然后就打了一个补丁。 其实也不能说MYSQL的代码有问题,GBK中的确没有0x80这个字符。但是cp936中有。可是cp936又不是标准,因为即便是微软内部,不同的windows版本的CP936范围都不一样。
编码的问题害死很多人啊http://rdc.taobao.com/blog/cs/?p=679
以下是常见的编码参数:
解码和编码时可以选择码和出错时的处理方式,错误处理方式一般有三种:
1) strict,出错时抛出UnicodeDecodeError异常。
2) ignore,出错时忽略不可转换字符。
3) replace,出错时使用?代替不可转换字符。
以下是解码和编码函数。
def decode(self, encoding=None, errors=None): # real signature unknown; restored from __doc__ """ S.decode([encoding[,errors]]) -> string or unicode Decodes S using the codec registered for encoding. encoding defaults to the default encoding. errors may be given to set a different error handling scheme. Default is 'strict' meaning that encoding errors raise a UnicodeDecodeError. Other possible values are 'ignore' and 'replace' as well as any other name registered with codecs.register_error that is able to handle UnicodeDecodeErrors. """ return "" def encode(self, encoding=None, errors=None): # real signature unknown; restored from __doc__ """ S.encode([encoding[,errors]]) -> string or unicode Encodes S using the codec registered for encoding. encoding defaults to the default encoding. errors may be given to set a different error handling scheme. Default is 'strict' meaning that encoding errors raise a UnicodeEncodeError. Other possible values are 'ignore', 'replace' and 'xmlcharrefreplace' as well as any other name registered with codecs.register_error that can handle UnicodeEncodeErrors. """ return ""
对于A/B两种编码方式,两者转换的示意图如下所示:
BOM
实际上UTF-8编码分为带BOM和不带BOM两种:
如果文本是UTF-8带BOM的话,会有其他乱码出现,或者有报错信息。
使用codecs模块可以很方便地处理带BOM的UTF-8文件。
# coding:utf-8 import locale import codecs filehandle = open(r'E:\test.txt', 'r') firstline = filehandle.readline() if firstline[:3] == codecs.BOM_UTF8: print(firstline[3:].decode('utf-8')) print("The locale is:") print(locale.getdefaultlocale()) print(filehandle.readline().decode('utf-8').encode('gbk')) filehandle.close()
以下是关于BOM的相关知识:
Unicode存储有字节序问题,例如“汉”一字,的Unicode编码0x6C49。存储时,6C写在前面,则称谓Big Endian,将49写在前面则称为Little Endian。UTF-8一般不需要BOM来表标明字节序,但还是可以用BOM标明。字符Zero Width No-Break Space的UTF-8编码是ef bb bf。所以如果接受者接收到ef bb bf开头的字节流,就知道是UTF-8编码吧。
例子2
s = 'python 中文测试' print(s)
由于Python默认编码为ASCII编码,代码中包含中文将会报错。如果需要使用中文,需要指定编码方式。
编码方式的声明有三种格式,可以用正则表达式来总结这三种编码方式 coding[:=]\s*([-\w.]+),符合这个正则表达式的都是有效的,比如
#哈哈哈coding: utf-8 哈哈哈 #fuckingcoding: utf-8 #fuckingcoding= utf-8
但下面是无效的,因为:和=前面多了空格。
#哈哈哈coding : utf-8 哈哈哈 #fuckingcoding : utf-8 #fuckingcoding = utf-8
以下是三种可选的声明方式
第一种声明方式: #coding= <encoding name> #coding= utf-8 第二种声明方式: #!/usr/bin/python # -*- coding:<encoding name> -*- 第三种声明方式: #!/usr/bin/python #vim: set fileencoding=<encoding name>
加上编码声明后,示例二可以正常输出。
例子3
如下所示,当str字符串和Unicode字符串连接时,会产生以下报错信息。由于先使用了ASCII对字符串进行解码再编码成UTF-8,ASIC无法正常识别中文编码,故产生报错。# coding= utf-8 s = "中文测试"+u"Chinese Test" print(s)
解决以上问题,有三种思路。
1)使用正确的解码方式(以python文本的编码方式作为解码)。
# coding= utf-8 s = "中文测试".decode('utf-8')+u"Chinese Test" print(s)
2)对Unicode字符串进行编码
# coding= utf-8 s = "中文测试"+u"Chinese Test".encode('utf-8') print(s)
3)Python2.6之后,可以通过from future import unicode_literals自动转义str字符串为Unicode字符串。
# coding= utf-8 from __future__ import unicode_literals s = "中文测试"+u"Chinese Test".encode('utf-8') print(s)
相关文章推荐
- == 和 != 有点靠不主,建议在进行比较的时候尽可能的使用Equals
- 一般性建议 使用多线程时要考虑以下准则
- 编写高质量代码改善C#程序的157个建议——建议135: 考虑使用肯定性的短语命名布尔属性
- 关于python中的unicode字符串的使用
- Python――深入理解urllib、urllib2及requests(requests不建议使用?)
- 使用python将用ASCII表示的16进制unicode编码的ASCII字符串转换为unicode字符串
- MarkFor Python 注册码 仅供学习使用 觉得pycharm好用 建议购买正版
- 对于Python装饰器使用的一些建议
- 对于Python装饰器使用的一些建议
- 建议124:考虑在命名空间中使用复数
- 一般性建议 使用多线程时要考虑以下准则
- 001_020 Python 使用Unicode来处理国际化文本
- 写python时注意使用unicode注释中文
- 编写高质量代码改善C#程序的157个建议——建议124:考虑在命名空间中使用复数
- Python-正确使用Unicode
- 使用python查询中文汉字的Unicode
- 【语言处理与Python】3.3使用Unicode进行文字处理
- Python中字符编码简介、方法及使用建议
- 建议13:使用Python模块re实现解析小工具
- 建议135: 考虑使用肯定性的短语命名布尔属性