您的位置:首页 > 编程语言 > Python开发

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

2019-06-30 23:13 190 查看
版权声明:署名,允许他人基于本文进行创作,且必须基于与原先许可协议相同的许可协议分发本文 (Creative Commons

通过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-8 UTF-16 UTF-32 UCS-2 UCS-4
    编码空间 0-10FFFF 0-10FFFF 0-10FFFF 0-FFFF 0-7FFFFFFF
    最少编码字节数 1 2 4 2 4
    最多编码字节数 4 4 4 2 4
    是否依赖字节序

    有些的地方也说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格式

    参考资料

    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: