zoukankan      html  css  js  c++  java
  • python中的字符编码(二)

    在上一小节的学习中,我们解决了python解析器输出汉字乱码的问题。但是一些关于编码的概念并没有解析清楚。这一小节,将继续学习字符编码的知识。

    先提出以下问题:

    1.什么是字符编码?

    2.什么是ACSII编码?

    3.什么是Unicode编码?

    4.什么是UTF-8编码?

    5.什么是cp950编码?

    在开始之前我们需要先理解什么是编码?

    在一些电影情节中,我们经常会看到某个活动于“地下的英雄们”在做一些不法活动时,通常用手电的“明,灭”或者“在空中画个大圈圈”来向对方传递某种不为人知的信息。在这里手电的明灭就是一种信息编码,传递了双方事先约定好的信息,比如“亮-灭--亮-灭”表示危险取消交易,“画个大圈圈”表示OK,安全可以交易。

    图1

    从图1我们可以知道,把信息以事先约定好的规则(编码原则)转化为另一种方式(方便使用工具传播比如手电的光信号),这就是对信息编码。

    A把信息“有危险取消交易”的信息转换为手电信号“亮-灭-亮-灭”这个过程是编码(encode)。

    B收到信号“亮-灭-亮-灭”根据事先约定的信息把这个信号翻译为“有危险取消交易”这个过程是解码(decode)。

    再更进一步学习字符编码前,先学习下字符在内存中的存储。在X86CPU计算机实现中规定(X86表示CPU指令集,详细信息参考维基百科条目):

    8位二进制代码称为一个字节(byte)。

    双字节16位二进制代码表示为一个字(word)。

    双字32位二进制代码表示为双倍字(dword)。

    4个字64位二进制代码表示为四倍字(qword)。

    字节是计算存储的最小单位,也是内存地址编码的最小单位。操作系统为内存单元也就是为每个字节指定一个值,这就是我们在上一节中使用id()可以输出的内容。

    而在数据存储上又有“大小端之分”。

    0A是最高有效位,存储在内存的低地址位,这称为大端序。

    0A是最高有效位,存储在内存的高地址,这称为小端序。

    (上图来源维基百科,参考文末链接)

    我们都知道在计算机内部CPU执行的指令都是01二进制代码,如果计算机只能输入和输出01代码,阅读起来太过痛苦也不便于计算机的推广使用,于是ASCII编码就被开发出来,用01序列来表示我们人类可以识别的自然语言。

    ASCII(American Standard Code for Information Interchange 美国信息交换标准代码)采用了一个字节来编码英文世界的信息。

    具体来说只使用了低7位(第八位也就是最高位默认为0,第一位又称为最低位),127个字符就满足了英文编码的需要。

    图2

    图3来源于维基百科

    0~32和第127个位置,总共33个控制字符,控制字符不会在终端(显示器)上显示主要用来实现特殊的目的,比如换行和退格。

    在编程中经常使用的是第10个字符换行和第十三个回车键(enter键)。这个一部分符号历史可以追溯那种古老的机械打印机。

    余下94个字符都是可以显示字符,其中48~57表示数字0~9,第65~90表示大写字母‘A’~‘Z’,第97~122表示小写字母'a'~'z'

    (更容易阅读的ASCII表见文末)

    随着计算机在全世界范围内广泛使用,ASCII不能满足更广范围的编码需求,比如汉字的编码,目前的GB2312汉字编码是使用两个字节来实现汉字的编码的,

    理论上可以实现256*256 = 65536个汉字。但是目前统计说有10万汉字,要想实现这么多的汉字编码就需要使用Unicode编码,当然在存储上会占用更多的字节。

    Unicode用来解决全世界范围内的字符编码问题。Unicode像ASCII一样只是定义了二进制字符序列与字符的对照关系。

    我们测试下一个汉字采用ASCII编码和Unicode会有什么区别。

    在windows记事本,中输入汉字“万”,分别另存为,ANSI编码,Unicode编码,Unicode bigendian编码和UTF-8编码。

    然后是用UltaEdit的切换16进制模式查看。

    汉字 “万” 
    ANSI编码:C9 45
    Unicdoe编码: FF FE 07 4E
    Unicode Bigendian:FE FF 4E 07
    UTF-8: EF BB BF E4 B8 87 

    (这例子学习自阮一峰的blog,阮大师举例为“严”,这里采用“万”字,是为了自己学习,链接见文末)

    “万”的Unicode的编码可以在“Unicode与汉字对照表”查到是“4E07”说明对照表中编码是Big endian的。

    记事本中的Unicode是采用little endian方式存储的,双字节的UCS2实现。

    Unicode规范中定义,每一个文件的最前面分别加入一个表示编码顺序的字符,这个字符的名字叫做"零宽度非换行空格"(ZERO WIDTH NO-BREAK SPACE),用FEFF表示。这正好是两个字节,而且FF比FE大1。
    如果一个文本文件的头两个字节是FE FF,就表示该文件采用大头方式;如果头两个字节是FF FE,就表示该文件采用小头方式。(摘自阮一峰blog)

    UTF-8以EF,BB,BF开头表示文档的编码格式,实际上“万”字的UTF-8表示为:E4 B8 87

    通过上面的例子我们可以看到UTF-8与Unicode编码不同,UTF-8是Unicode的一种实现方式。UTF-8编码采用了变长的字节存储比Unicode节省空间,且兼容ASCII字符,是目前网络最通用的一种编码方式。

    在我们最后的一个问题中的cp950是“操作系统实现的字符集”,这个在windows中表示繁体字符集。

    在python2.7中已经支持了Unicode字符集,在不同的字符集之间切换需要借助utf-8编码为中间码做转换,然后再转换为目标字符集。

    print(msg.decode("utf-8").encode("950"))

    参考资料:

    字符编码

    http://zh.wikipedia.org/zh-cn/%E5%AD%97%E7%AC%A6%E7%BC%96%E7%A0%81

    ASCII

    http://zh.wikipedia.org/wiki/ASCII

    32位元

    http://zh.wikipedia.org/wiki/32%E4%BD%8D

    unicode与汉字对照表

    http://www.chi2ko.com/tool/CJK.htm

    unicode

    http://zh.wikipedia.org/wiki/Unicode

    关于大端和小端

    http://zh.wikipedia.org/wiki/%E5%AD%97%E8%8A%82%E5%BA%8F

    UTF-8

    http://zh.wikipedia.org/wiki/UTF-8

    阮一峰blog

    http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html

    以下表格整理在维基百科

    二进制 十六进制 十进制 缩写 Unicode 脱出字符 名称/意义
    表示法 表示法
    0000 0000 0 0 NUL ^@ 空字符(Null)
    0000 0001 1 1 SOH ^A 标题开始
    0000 0010 2 2 STX ^B 本文开始
    0000 0011 3 3 ETX ^C 本文结束
    0000 0100 4 4 EOT ^D 传输结束
    0000 0101 5 5 ENQ ^E 请求
    0000 0110 6 6 ACK ^F 确认回应
    0000 0111 7 7 BEL ^G 响铃
    0000 1000 8 8 BS ^H 退格
    0000 1001 9 9 HT ^I 水平定位符号
    0000 1010 0A 10 LF ^J 换行键
    0000 1011 0B 11 VT ^K 垂直定位符号
    0000 1100 0C 12 FF ^L 换页键
    0000 1101 0D 13 CR ^M Enter键
    0000 1110 0E 14 SO ^N 取消变换(Shift out)
    0000 1111 0F 15 SI ^O 启用变换(Shift in)
    0001 0000 10 16 DLE ^P 跳出数据通讯
    0001 0001 11 17 DC1 ^Q 设备控制一(XON 激活软件速度控制)
    0001 0010 12 18 DC2 ^R 设备控制二
    0001 0011 13 19 DC3 ^S 设备控制三(XOFF 停用软件速度控制)
    0001 0100 14 20 DC4 ^T 设备控制四
    0001 0101 15 21 NAK ^U 确认失败回应
    0001 0110 16 22 SYN ^V 同步用暂停
    0001 0111 17 23 ETB ^W 区块传输结束
    0001 1000 18 24 CAN ^X 取消
    0001 1001 19 25 EM ^Y 连接介质中断
    0001 1010 1A 26 SUB ^Z 替换
    0001 1011 1B 27 ESC ^[ 退出键
    0001 1100 1C 28 FS ^\ 文件分区符
    0001 1101 1D 29 GS ^] 组群分隔符
    0001 1110 1E 30 RS ^^ 记录分隔符
    0001 1111 1F 31 US ^_ 单元分隔符
     
    0111 1111 7F 127 DEL ^? 删除
    二进制 十六进制 十进制 图形
    0010 0000 20 32 (空格,␠)
    0010 0001 21 33 !
    0010 0010 22 34 "
    0010 0011 23 35 #
    0010 0100 24 36 $
    0010 0101 25 37  %
    0010 0110 26 38 &
    0010 0111 27 39 '
    0010 1000 28 40 (
    0010 1001 29 41 )
    0010 1010 2A 42 *
    0010 1011 2B 43 +
    0010 1100 2C 44 ,
    0010 1101 2D 45 -
    0010 1110 2E 46 .
    0010 1111 2F 47 /
    0011 0000 30 48 0
    0011 0001 31 49 1
    0011 0010 32 50 2
    0011 0011 33 51 3
    0011 0100 34 52 4
    0011 0101 35 53 5
    0011 0110 36 54 6
    0011 0111 37 55 7
    0011 1000 38 56 8
    0011 1001 39 57 9
    0011 1010 3A 58 :
    0011 1011 3B 59 ;
    0011 1100 3C 60 <
    0011 1101 3D 61 =
    0011 1110 3E 62 >
    0011 1111 3F 63 ?
           
    0100 0000 40 64 @
    0100 0001 41 65 A
    0100 0010 42 66 B
    0100 0011 43 67 C
    0100 0100 44 68 D
    0100 0101 45 69 E
    0100 0110 46 70 F
    0100 0111 47 71 G
    0100 1000 48 72 H
    0100 1001 49 73 I
    0100 1010 4A 74 J
    0100 1011 4B 75 K
    0100 1100 4C 76 L
    0100 1101 4D 77 M
    0100 1110 4E 78 N
    0100 1111 4F 79 O
    0101 0000 50 80 P
    0101 0001 51 81 Q
    0101 0010 52 82 R
    0101 0011 53 83 S
    0101 0100 54 84 T
    0101 0101 55 85 U
    0101 0110 56 86 V
    0101 0111 57 87 W
    0101 1000 58 88 X
    0101 1001 59 89 Y
    0101 1010 5A 90 Z
    0101 1011 5B 91 [
    0101 1100 5C 92 \
    0101 1101 5D 93 ]
    0101 1110 5E 94 ^
    0101 1111 5F 95 _
           
    0110 0000 60 96 `
    0110 0001 61 97 a
    0110 0010 62 98 b
    0110 0011 63 99 c
    0110 0100 64 100 d
    0110 0101 65 101 e
    0110 0110 66 102 f
    0110 0111 67 103 g
    0110 1000 68 104 h
    0110 1001 69 105 i
    0110 1010 6A 106 j
    0110 1011 6B 107 k
    0110 1100 6C 108 l
    0110 1101 6D 109 m
    0110 1110 6E 110 n
    0110 1111 6F 111 o
    0111 0000 70 112 p
    0111 0001 71 113 q
    0111 0010 72 114 r
    0111 0011 73 115 s
    0111 0100 74 116 t
    0111 0101 75 117 u
    0111 0110 76 118 v
    0111 0111 77 119 w
    0111 1000 78 120 x
    0111 1001 79 121 y
    0111 1010 7A 122 z
    0111 1011 7B 123 {
    0111 1100 7C 124 |
    0111 1101 7D 125 }
    0111 1110 7E 126 ~
  • 相关阅读:
    ie不支持 event.stopPropagation 的解决方式
    jquery 获取 元素.text( ) 里面的值 需要进行去空格去换行符操作
    使用插件实现某元素展示特定行文字,超出显示...
    css文字超出显示省略号
    纯css实现各种三角形图案
    jQuery判断鼠标是否在某个元素内
    z-tree相关设置
    js提取字符串中的汉字
    扩展ie中不兼容的startsWith,endsWith方法
    获取浏览器URL携带过来的参数/获取url中"?"符后的字串
  • 原文地址:https://www.cnblogs.com/mengfanhao/p/3119003.html
Copyright © 2011-2022 走看看