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

参考资料:

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

python与编码的更多相关文章

  1. python Unicode 编码解码

    1 #将Unicode转换成普通的Python字符串:"编码(encode)" 2 unicodestring = u"Hello world" 3 utf8s ...

  2. python的编码问题

    本文简单介绍了各种常用的字符编码的特点,并介绍了在python2.x中如何与编码问题作战 :) 请注意本文关于Python的内容仅适用于2.x,3.x中str和unicode有翻天覆地的变化,请查阅其 ...

  3. python 字符编码练习

    通过下面的练习,加深对python字符编码的认识 # \x00 - \xff 256个字符 >>> a = range(256)>>> b = bytes(a) # ...

  4. Python 字符编码 zz

    http://www.cnblogs.com/huxi/archive/2010/12/05/1897271.html 1. 字符编码简介 1.1. ASCII ASCII(American Stan ...

  5. python 之编码问题详解

    前在一个项目中遇到用post提交一个xml,xml中含有中文,对于单独的py文件,使用urllib2.urlopen完全ok,但在django中使用就一直报编码错误,然后在网上看到这篇文章不错,决定m ...

  6. 19.python的编码问题

    在正式说明之前,先给大家一个参考资料:戳这里 文章的内容参考了这篇资料,并加以总结,为了避免我总结的不够完善,或者说出现什么错误的地方,有疑问的地方大家可以看看上面那篇文章. 以下说明是针对于pyth ...

  7. Python字符编码详解

    1. 字符编码简介 1.1. ASCII ASCII(American Standard Code for Information Interchange),是一种单字节的编码.计算机世界里一开始只有 ...

  8. python的编码

    python的编码 1.概述 讲述编码,那么就要涉及到几个方面,包括系统中如何来显示字符,文件中如何来保存字符. 1.1 系统环境 在系统中显示字符,那么就必须要考虑到系统中使用的编码格式. 在lin ...

  9. 【转】Python字符编码详解

    转自:http://www.cnblogs.com/huxi/archive/2010/12/05/1897271.html 1. 字符编码简介 1.1. ASCII ASCII(American S ...

随机推荐

  1. Python导入自定义包或模块

    一般我们会将自己写的 Python 模块与 Python 自带的模块分开存放以达到便于维护的目的. Python 运行环境在查找模块时是对 sys.path 列表进行遍历,如果我们想在运行环境中添加自 ...

  2. react项目组件化思考

    三个原则 single store render from top immutable data single store,便于组件之间通信. render from top,因为store就一个,每 ...

  3. POJ 2175 Evacuation Plan 费用流 负圈定理

    题目给了一个满足最大流的残量网络,判断是否费用最小. 如果残量网络中存在费用负圈,那么不是最优,在这个圈上增广,增广1的流量就行了. 1.SPFA中某个点入队超过n次,说明存在负环,但是这个点不一定在 ...

  4. SQL Server中的事务日志管理(4/9):简单恢复模式里的日志管理

    当一切正常时,没有必要特别留意什么是事务日志,它是如何工作的.你只要确保每个数据库都有正确的备份.当出现问题时,事务日志的理解对于采取修正操作是重要的,尤其在需要紧急恢复数据库到指定点时.这系列文章会 ...

  5. 【转】IOS开发中图片资源使用png还是jpg格式

    对于iOS本地应用程序来说最简单的答案就是始终使用PNG,除非你有非常非常好的理由不用它. 当iOS应用构建的时候,Xcode会通过一种方式优化.png文件而不会优化其它文件格式.它优化得相当的好 他 ...

  6. PowerMock使用遇到的问题——1

    遇到问题:再用PowerMock Mock构造方法时,所有语句都可以通过执行,但当最后执行verify语句时却总是出现如下错误:         java.lang.AssertionError:   ...

  7. Velocity语法--转载

    Velocity是一个基于java的模板引擎(template engine),它允许任何人仅仅简单的使用模板语言(template language)来引用由java代码定义的对象.作为一个比较完善 ...

  8. 基于PHP的crontab定时任务管理

    BY JENNER · 2014年11月10日· 阅读次数:6 linux的crontab一直是server运维.业务开展的利器.但当定时任务增多时,管理和迁移都变得非常麻烦,并且easy出问题.以下 ...

  9. 201521123117 《Java程序设计》第6周学习总结

    1. 本周学习总结 2. 书面作业 Q1.clone方法 1.Object对象中的clone方法是被protected修饰,在自定义的类中覆盖clone方法时需要注意什么? 答:在自定义的类中覆盖cl ...

  10. C#百度图片识别API调用返回数据包解析

    百度图片识别api接口 public static JObject GeneralBasic(string apikey,string secretkey,string path) { var cli ...