【Python杂烩】通过Python学习字符串编码

通过Python学习字符串编码

  • 字符串的编码和解码
    • 到底什么是编码,什么是解码?
  • 字符编码标准
    • 什么是Unicode?
    • 历史发展
    • Unicode 与 UTF 的关系
    • UTF32与USC-4, UTF16与USC-2
    • 有些的地方也说Unicode是具体的编码?
  • python字符串编码

字符串的编码和解码


到底什么是编码,什么是解码?

在了解什么是编码解码之前,我们得先来了解一下什么是字符(character)字节流(byte streams)

  • 字符是我们可以识别看懂的文字
  • 字节流则是字符按某种编码格式编码后的二进制存储格式,是用于给计算机存储和识别的

那么什么是编码,什么又是解码呢?

  • 将字符转换为字节流的过程,我们称之为编码
  • 将字节流转换为字符的过程,我们称之为解码

总的来说就是,把人类所使用的这些字符集转换为计算机所能理解的二级制码,这个过程就是编码,他的逆过程称为解码。


字符编码标准


什么是Unicode?

Unicode是统一码,万国码,单一码,是计算机科学领域的一项行业标准。它包括字符集,编码方案等。Unicode是为了解决传统字符编码方案的局限性而产生的。它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言,跨平台进行文本转换,处理的要求。@百度百科


历史发展

字符串也是一种常见的普通数据类型,每种编程语言都有,只不过字符串相比其他数据类型而言,还带有一个编码问题。

阶段一:

  • 我们知道计算机是只能处理数字的,既只认识0,1。 所以当我们的基本数据类型字符串要被计算机处理时,就必须将字符转换成二进制的数字格式。
  • 我们也知道计算机是美国发明的,而美国是一个英语系的国家,所以在考虑计算机的问题时,主要也是站在英语系文字的角度去考虑这个问题,所以在早期,只有127个英文字母和一些简单的符号才能被计算机所识别, 因为英文所需要的字符不多,所以所有的字符串对应到计算机的存储格式都只有一个字节,而一个字节(8位)能表示256种字符,一个字节表示还有剩余的空间。而字符和二进程存储的映射则由一份编码表来维护,也就是我们所知道的ASCII编码。
  • 此阶段只用了8位的低位空间,既00000000~01111111, 也即是0~127

阶段二:

  • 随着计算机被迅速的推广和使用,欧洲非英语国家的计算机大牛就发现,这一套美国设计的字符集Too Young Too Simple, 很多其他拉丁字符语言文字根本不够用呀。于是大牛们就在ASCII占用一个字节内存的剩余空间位置又拓展出来了一些字符,填满256, 补充了ASCII编码
  • 此阶段又补充了高位空间,利用了10000000~11111111, 既128~255的剩余位置,一个字节的空间已经被完全的利用完了。

阶段三

  • 随着使用计算机的国家越来越多,已经不再局限什么西欧国家了。中文,韩文,日本以及各种未知文都需要一个字符映射的存储呀。当初ASCII也是Too Young Too Simple, 一个字节怎么能够用呢。我大中华文化博大精深,单单是中文就不够存储了,怎么办怎么办?于是中国国家标准总局发布了一套《信息交换用汉字编码字符集》的国家标准,其标准号就是GB 2312—1980。这个字符集共收入汉字6763个和非汉字图形字符682个,采用两个字节对字符集进行编码,并向下兼容ASCII编码方式。再后来生僻字、繁体字及日韩汉字也被纳入字符集,就又有了后来的GBK字符集及相应的编码规范,GBK编码规范也是向下兼容GBK2312的
  • 当然中国有GBK格式,韩国有EUC-KR,日本也有Shift_JIS。总之每个国家都出现了一系列的字符编码格式,可谓是百家争鸣,但又相互不兼容…

阶段四

  • 随着各个国家出现了各种的编码格式,也出现了越来越多互相不兼容的情况,不同的语言字符编码值相同,但却代表不同的字符,例如韩文编码EUC-KR中“한국어”的编码值正好是汉字编码GBK中的“茄惫绢”。因此如果同一份文本文件,拷贝到互不兼容的不同语言编码格式的计算机上,就很有可能出现乱码。所以此时的人们就会想 “我们能不能定义一个超大的字符集,它可以容纳全世界所有的文字字符,再对它们统一进行编码,让每一个字符都对应一个不同的编码值,从而就不会再有乱码了”

  • 如果说 “各个国家都在为自己文字独立编码” 是百家争鸣,那么 “建立世界统一的字符编码” 则是一统江湖,谁都想来做这个武林盟主。早前就有两个机构试图来做这个事:
    (1) 国际标准化组织(ISO),他们于1984年创建ISO/IEC JTC1/SC2/WG2工作组,试图制定一份“通用字符集”(Universal Character Set,简称UCS),并最终制定了ISO 10646标准。
    (2) 统一码联盟,他们由Xerox、Apple等软件制造商于1988年组成,并且开发了Unicode标准(The Unicode Standard

  • 1991年前后,两个项目的参与者都认识到,世界不需要两个不兼容的字符集。于是,它们开始合并双方的工作成果,并为创立一个单一编码表而协同工作。 从Unicode 2.0开始,Unicode采用了与ISO 10646-1相同的字库和字码;ISO也承诺,ISO 10646将不会替超出U+10FFFF的UCS-4编码赋值,以使得两者保持一致。两个项目仍都独立存在,并独立地公布各自的标准。不过由于Unicode这一名字比较好记,因而它使用更为广泛

简单小结

  • 总之呢,从一开始128到256的ASCII编码,再到各种编码格式的百家争鸣,再到Unicode的统一江湖。我们也可以简单的知道了字符串编码的历史和发展。Unicode的出现就是为了让大家不要再为使用那种编码格式而烦恼
  • Unicode虽然出现了,但是Unicode编码规范仅仅是字符码位的定义,属于字符集,不属于编码。所以为了更好的采用和实现Unicode字符集,后面也就出现了以UTF8,UTF16,UTF32为代表的字符串UTF编码格式,可以针对Unicode字符串对字符串进行编码和解码
  • 当然不管编码格式怎么发展,都要记住一点ASCII对待西方拉丁文字而言是具有必要意义的,比如GBK,UTF8都是向下兼容ASCII编码格式的

详细可以查看一下三篇的文章奥


Unicode 与 UTF 的关系

@百度百科
Unicode是统一码,万国码,单一码,是计算机科学领域的一项行业标准。它包括字符集,编码方案等。Unicode是为了解决传统字符编码方案的局限性而产生的(从上面历史发展就可以看到)。它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言,跨平台进行文本转换,处理的要求。

  • 从广义上来说,Unicode包括Unicode字符集编码方案等。既Unicode字符集(字符与二进制编码的映射),以及实际编码方案UTF8,UTF16,UTF32都属于Unicode的范畴;从狭义的说,Unicode也被通常指为是Unicode字符集。实际上不管是Unicode字符集还是编码方案,它都属于Unicode。所以当某人说某种语言的默认字符编码为Unicode,那么该字符编码可能是UTF8,16,32的任意一种奥~

  • 狭义上的Unicode通常指的是Unicode字符集规范,定义了所有字符的码位。而实际的字符编码方案则是UTF编码Unicode字符集UTF8的关系,我们可以理解为一个是规范,一个是具体的实现者。既UTF8是Unicode字符集的具体编码方案。举个粟子,假如'中'字符在Unicode字符集的码位是789,那么就要'中'字符的 “代号: 789” 要转成怎么样的二进制数值在计算机中存储呢?以几个字节的方式存储呢?如果是UTF8可能是1~4字节,UTF16可能是2~4个字节,UTF32就是4个字节了。同样的Unicode码位,不同的编码方案,就有不同的存储方式。('中’的码位是随便说的哈)

  • 既Unicode字符集定义了具体字符的 “代号” ,而不同的UTF编码方案则决定了这些 “代号” 在内存中以多大的大小去存储


UTF32与USC-4, UTF16与USC-2

引用至@细说:Unicode, UTF-8, UTF-16, UTF-32, UCS-2, UCS-4 - @作者:Malecrab
utf32与usc-4

  • 在Unicode与ISO 10646合并之前,ISO 10646标准为“通用字符集”(UCS)定义了一种31位的编码形式(即UCS-4),其编码固定占用4个字节,编码空间为0x00000000~0x7FFFFFFF(可以编码20多亿个字符)。

  • UCS-4有20多亿个编码空间,但实际使用范围并不超过0x10FFFF,并且为了兼容Unicode标准,ISO也承诺将不会为超出0x10FFFF的UCS-4编码赋值。由此UTF-32编码被提出来了,它的编码值与UCS-4相同,只不过其编码空间被限定在了0~0x10FFFF之间。因此也可以说:UTF-32是UCS-4的一个子集

.
utf16与usc-2

  • 除了UCS-4,ISO 10646标准为“通用字符集”(UCS)定义了一种16位的编码形式(即UCS-2),其编码固定占用2个字节,它包含65536个编码空间(可以为全世界最常用的63K字符编码,为了兼容Unicode,0xD800-0xDFFF之间的码位未使用)。例:“汉”的UCS-2编码为6C49。

  • 但俩个字节并不足以正真地“一统江湖”(a fixed-width 2-byte encoding could not encode enough characters to be truly universal),于是UTF-16诞生了,与UCS-2一样,它使用两个字节为全世界最常用的63K字符编码,不同的是,它使用4个字节对不常用的字符进行编码。UTF-16属于变长编码


UTF8, UTF16 , UTF32的区别

UTF8,16,32都属于Unicode字符集的UTF编码方案

  • 他们的不同之处是对待同一个Unicode字符编码需要多大的内存空间去存储。比如字符'A', UTF8只需要1个字节,UTF16则需要2个字节,UTF32则需要4个字节。不同的内存空间需求,就造成了不同的场景需要。需要的内存空间越小,在字符传输,存储,处理上性能就更加优秀。但世界上字符这么多,并不是所有字符都能由8位(一字节)的空间大小去存储的。所以才诞生了UTF8,16,32各种编码方案,这些编码方案也各有各的优势和通行场景。

UTF8:

  • 存在单字节编码(所以兼容ASCII编码)
  • 属于变长存储编码,最少1字节,最多4字节
  • 相比UTF16,32而言,没有字节序的问题

UTF16:

  • 半固长存储编码,大部分字符以2字节存储,偏颇生词使用4字节存储,既2~4字节
  • 有字节序问题 ,有大端小端之分

UTF32

  • 固长存储编码,所有字符都以4字节存储
  • 因为固长,所以便于处理,属于空间换时间的手段
  • 有字节序问题 ,有大端小端之分

区别表格:

对比UTF-8UTF-16UTF-32UCS-2UCS-4
编码空间0-10FFFF0-10FFFF0-10FFFF0-FFFF0-7FFFFFFF
最少编码字节数12424
最多编码字节数44424
是否依赖字节序

有些的地方也说Unicode是具体的编码?

为什么?

  • 为什么有一些地方会说计算机内存中使用的是Unicode编码,内存读取外部UTF8编码文件时,需要将UTF8转换为Unicode格式。对外展示的时候,又需要将unicode转换成utf8格式,这样的说法准确吗?

下文都提到了unicode编码与utf编码的转换

解释

  • 这种说法准确,但是具有很大的误导性,可以说是windows历史遗留下来的坑。通常我们所说的windows内存默认编码unicode, 实际并不是"unicode"本身, 而是utf-16le编码,既window内存的实际默认编码是utf-16le。然而国内有一些博客和文章都没有明说出这一点,也没有区分这一点,导致大量博客的转载或是XXX, 最后约定大于规定,就造成一定的概念混乱(所以有的时候还是建议直接看英文原文文章会更加容易理解

为什么windows要采用utf16le呢,而不统一采用utf8

  • Windows身上的“历史原因”,在于Unicode标准初生的时候,字符码其实是16位,那个时候的UTF-16就能直接保存Unicode字符码。于是Windows就直接将自己使用的UTF-16 LE编码命名为“Unicode",这在当时是名符其实的。但是后来西方人尴尬地发现如果把中国人故纸堆里的罕用字,各种小语种的文字都收进去的话,16位65536个码位仍然是不够用的。Unicode升级成了32位,出现了字符码突破16位的字符,UTF-16从定长码变成了不定长码,对于Windows来说,这就很坑爹了。尽管字符码在16位以内的字符,UTF-16编码仍然保持不变,但还是很坑爹 来源知乎 - @作者:farta

  • 曾经的utf16le是2字节(16位)为主,而utf8从1~4字节的形式都有,因为格式的多样,对计算机的处理其实并没有这么的友好,毕竟如果大部分甚至所有字符都是一样的字节格式(比如16位)会更具有通用性,所以当初windows内存的默认编码是utf16le而为什么外部文件系统常用utf8呢? 也正因为utf8格式多样,从2字节到4字节都有,对待不同的字符串采用不同的格式进行存储,可以最大的节省空间(尤其是西方文字)。所以通常在传输文件存储方面,utf8式的unicode编码格式使用的更加广泛。也就会出现文件存储以utf8格式,被内存读取时,又要将utf8转换为utf16le


python字符串编码


python3默认的字符串编码就是unicode, utf-8就是unicode字符码位的具体二进制存储格式

# windows 10
import sys
import locale
print(sys.getdefaultencoding()) # 系统默认编码,不要把系统以为是操作系统,这里可以理解成python3的编译器本身
print(locale.getdefaultlocale()) # 本地默认编码,这个才是操作系统的编码,cp936也就是gbk
print(sys.getfilesystemencoding())
print(sys.stdin.encoding)
print(sys.stdout.encoding)
"""
output:
utf-8
('zh_CN', 'cp936') 
utf-8
UTF-8
UTF-8
"""
  • 我们可以看到Python3的编译器,文件系统,输入输出的字符串默认编码都是unicode编码的utf8格式

参考资料


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值