再谈Python中的字符串与字符编码(推荐)

论坛 期权论坛 脚本     
niminba   2021-5-23 04:09   1214   0

本节内容:

1.前言

2.相关概念

3.Python中的默认编码

4.Python2与Python3中对字符串的支持

5.字符编码转换

一、前言

Python中的字符编码是个老生常谈的话题,同行们都写过很多这方面的文章。有的人云亦云,也有的写得很深入。近日看到某知名培训机构的教学视频中再次谈及此问题,讲解的还是不尽人意,所以才想写这篇文字。一方面,梳理一下相关知识,另一方面,希望给其他人些许帮助。

Python2的 默认编码 是ASCII,不能识别中文字符,需要显式指定字符编码;Python3的 默认编码 为Unicode,可以识别中文字符。

相信大家在很多文章中都看到过类似上面这样“对Python中中文处理”的解释,也相信大家在最初看到这样的解释的时候确实觉得明白了。可是时间久了之后,再重复遇到相关问题就会觉得貌似理解的又不是那么清楚了。如果我们了解上面说的默认编码的作用是什么,我们就会更清晰的明白那句话的含义。

二、相关概念

1. 字符与字节

一个字符不等价于一个字节,字符是人类能够识别的符号,而这些符号要保存到计算的存储中就需要用计算机能够识别的字节来表示。一个字符往往有多种表示方法,不同的表示方法会使用不同的字节数。这里所说的不同的表示方法就是指字符编码,比如字母A-Z都可以用ASCII码表示(占用一个字节),也可以用UNICODE表示(占两个字节),还可以用UTF-8表示(占用一个字节)。字符编码的作用就是将人类可识别的字符转换为机器可识别的字节码,以及反向过程。

UNICDOE才是真正的字符串,而用ASCII、UTF-8、GBK等字符编码表示的是字节串。关于这点,我们可以在Python的官方文档中经常可以看到这样的描述"Unicode string" , " translating a Unicode string into a sequence of bytes"

我们写代码是写在文件中的,而字符是以字节形式保存在文件中的,因此当我们在文件中定义个字符串时被当做字节串也是可以理解的。但是,我们需要的是字符串,而不是字节串。一个优秀的编程语言,应该严格区分两者的关系并提供巧妙的完美的支持。JAVA语言就很好,以至于了解Python和PHP之前我从来没有考虑过这些不应该由程序员来处理的问题。遗憾的是,很多编程语言试图混淆“字符串”和“字节串”,他们把字节串当做字符串来使用,PHP和Python2都属于这种编程语言。最能说明这个问题的操作就是取一个包含中文字符的字符串的长度:

  • 对字符串取长度,结果应该是所有字符串的个数,无论中文还是英文
  • 对字符串对应的字节串取长度,就跟编码(encode)过程使用的字符编码有关了(比如:UTF-8编码,一个中文字符需要用3个字节来表示;GBK编码,一个中文字符需要2个字节来表示)

注意:Windows的cmd终端字符编码默认为GBK,因此在cmd输入的中文字符需要用两个字节表示

>>> # Python2
>>> a = 'Hello,中国' # 字节串,长度为字节个数 = len('Hello,')+len('中国') = 6+2*2 = 10
>>> b = u'Hello,中国' # 字符串,长度为字符个数 = len('Hello,')+len('中国') = 6+2 = 8
>>> c = unicode(a, 'gbk') # 其实b的定义方式是c定义方式的简写,都是将一个GBK编码的字节串解码(decode)为一个Uniocde字符串
>>> 
>>> print(type(a), len(a))
(<type 'str'>, 10)
>>> print(type(b), len(b))
(<type 'unicode'>, 8)
>>> print(type(c), len(c))
(<type 'unicode'>, 8)
>>>

Python3中对字符串的支持做了很大的改动,具体内容会在下面介绍。

2. 编码与解码

先做下科普:UNICODE字符编码,也是一张字符与数字的映射,但是这里的数字被称为代码点(code point), 实际上就是十六进制的数字。

Python官方文档中对Unicode字符串、字节串与编码之间的关系有这样一段描述:

Unicode字符串是一个代码点(code point)序列,代码点取值范围为0到0x10FFFF(对应的十进制为1114111)。这个代码点序列在存储(包括内存和物理磁盘)中需要被表示为一组字节(0到255之间的值),而将Unicode字符串转换为字节序列的规则称为编码。

这里说的编码不是指字符编码,而是指编码的过程以及这个过程中所使用到的Unicode字符的代码点与字节的映射规则。这个映射不必是简单的一对一映射,因此编码过程也不必处理每个可能的Unicode字符,例如:

将Unicode字符串转换为ASCII编码皇@]\/&c9:`+k.b{/g#].+\l,y+., #9d#iy[Xykhyk9cy+he,B B]\HHBH\H\NB[]BJH[Ν]N JCBBHH oIHIoIB[ \JJK[JJCB[ \JK[JCBB OB ]B/;B B \H  OB B \H XI O B] B]e,+c9.kl`(y."c%c[Xy9.. 9.*]\ .j:gh."iyc9..]d[Xyd"9.9... 9.B B]\HHBH\H\NB\]\XCB\XO OB ]Bkfay."]#,9.b:e&z+#9o 9i#c.b!ke,.#ke fi]m+he, #9ke+ey]\iz(j9.g+#]9k.byl,y+).,k.kPyay+#9an"f9ke,i!9-' B B]\HHBH\H\NB[]BJH[Ν]N JCBBHH oIHIoIH oI˙[J CBB[ \JJK[JJCB[ \JK[JCB[ \J[CBB OB ]B/;B B\ B B\ B B\ ]\ B.8ke%/k9h  B."gh,;SPyke,c#.#)kec9./k9hif& B[Y[HZZ[Z[[^][K NKYMY  NNMLYN LH B`)9ky$,9. 9.*e;l,y+#9ke%ke&/Xy./k9hd%e9b9+ B].+yke,/c9ke%/k9h/"&  Bke,KIXJ iyke%KIXyke,KIJ 9ke%KI.,B B]\HHBH\H\NB[]BJH[Ν]N JCBBB]H ,y.+yfBHH]XJ N [J CB[ KXJ JCB OB ]B/;B B$y.+yfB].byke,n9l,y+X{fi9.#zg :)yab:) {cy$99ke%  Bke,KIJ 9ke%KI.,B B]\HHBH\H\NB[]BJH[Ν]N JCBBB]H ,y.+yfBHH][J CB[ KXJ JCBB OB ]B/;B B$y.+yfB 9d#g :)z+#+Xy.#y+dn;.g+y+j;k#z . 9.*.+y$9. 9.*"h9ke%/k9h/"+#9. 9.*ke9kej9oho# #9ke+:.)c+:+'%fi9nm.#y+"yke%.b:/k9h`+#8#.b9)hВ y'9.+yf'z/k9$UN9ke%d#.+.*ke$9..*keiz(j9/aamkej9oho#:+++yf'{ #9.#yn:+$8'9/h9iox'y% !x'[x'x Bbczgh"y.o9i)ay.o9+d#gh-#9n#9&"y`9n+bxB B."l,y+j:`yk{n#9&)9ki.h9"y`9n+b{.g&i&i&+/c.

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:1060120
帖子:212021
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP