zoukankan      html  css  js  c++  java
  • 字符编码

    ASCII, ANSI, Unicode, GBK, GB2312, UTF-8; 437代码页,936代码页,,, 这都是些什么?乱糟糟的。。。
    
    网上海量的说明文章,按我自己的理解,总结一下:
    
    问题产生背景:(基础知识,可跳过)
    View Code
        1. 计算机如何存储 英文字母标点符号这一系列字符?
          最简单的思想就是给这一大堆字符规定个顺序,然后用自然数编号(注意:最小的自然数是0),
            只让计算机只存储这些字符的数字编号;至于如何在屏幕上呈现给人类的问题交给显示器去做;
        2. 各种字符编码集:
            我们知道计算机的最小存储单元是1字节共8位,1个存储单元的空间最多可以表示2^8=256种信息状态;
          计算机诞生于美国,美国人最开始定义了属于它们自己国家的一套编号"规定" 称为ASCII
        (American Standard Code for Information Interchange,美国信息互换标准代码)
            其中包含了美国人最常用的128个字符(编号从0~127),像美元货币字符$, 英文标点符号,数字,
        大小写的英文字母等;
            
            ASCII太倾向于美国人,英国人发现它们的货币字符 £ 都没有在这一套编号里,
            好在ASCII只占了1个存储单元一半的空间,于是在英国和欧洲不同的国家,为了和ASCII兼容,
            它们使用剩下的128~255个数字,表示属于它们民族专有的字符;称为扩展ASCII字符;
    
            ASCII太倾向于美国人,扩展ASCII太倾向于非亚洲人;对于中文语言来说,256个数字无法编号所有
            汉字,唯一的办法就是扩大存储空间,于是在中国和亚洲不同的国家,它们使用了多个存储单位来编号
           自己民族的专有字符;这样诞生了很多属于某个特定国家的“编号规定”,像中国的GB码,
        韩国euc-kr编码和日本的Shift_JIS编码等;
    
            这些多字节编码规则只是从本国语言需求而考虑的,一种存储数据在不同的国家,会被计算机识别
            为各种信息,这给数据共享带来很大麻烦;
    
         3. 数据共享
            为了解决"本地特色"的各种不同编码给数据共享带来的麻烦,Unicode编码诞生了,它在定义编号的时候
            不是从某一个国家的民族的需求出发,而是从全人类出发,不分国界,把所有国家,所有民族的字符
            都规定一个唯一自然数编号;
    
    

     各种字符编码集基本概念梳理

    View Code
    先说和ASCII兼容的问题:
      美国的文档资料很丰富,很重要,如何和他们的ASCII兼容?
      扩展ASCII字符集是单字节编码,在特定的国家它们很容易实现和ASCII的兼容,方法就是在1字节的高位做个标记
      如果高位为0表示美国人的ASCII字符,高位为1表示本国的特有字符;
    
    对于多字符编码的字符集,在本国该如何实现和ASCII的兼容:
      简单的方法是用2个字节,同扩展ASCII字符的做法,每个字节用ASCII字符后剩下的一半的编号,
      这样可以表示128*128=16384个字符;在识别的时候,如果发现某一字节的高位是1,则它是一个中文字符的一半,
          需要和另一半组合拼成一个完整的汉字;这样避免了识别时的歧义性;我称它为1类扩展ASCII码拼接法
    
    如果超过16384个字符,那怎么办? 
        我们定义第1字节为扩展ASCII码字符,第2字节编号范围在0~255;这样可以表示128*256 = 32768个字符;
        在让计算机识别的时候,从数据的最开始存储单元开始向后扫描,一旦发现有某个字节是扩展ASCII字符,
        那么不管它的下一个字符是扩展ASCII码还是ASCII,都作为中文字符的另一半参与拼接;
        然后,扫描工作从它的"下下"一个字符继续, 对于ASCII字符不需要做拼接处理;我称它为2类扩展ASCII拼接法;
    
    这两种拼接的方法很简单,都可兼容ASCII;但是都没被采用,原因可能是他们太浪费空间了;
    
    看看GB2312字符集(GB2312是信息交换用汉字编码字符集的标准号省去发布年份1980)的做法:
        它占用了94*94 = 8836 个编号,总共收录了包括7455个字符(简体汉字6763个)
        8836个编号划分了94区,每个区包含94个编号(称为该区的位号)
        分区的思想也许是为了统一管理和方便查询吧,比如中文标点符号放1个区,中文数字序号放在同2区;
        然后用第1字节(低字节)表示区号,第2字节(高字节)表示位号;存储的时候为了和ASCII兼容,每个编号+160;
        这种存储方法叫EUC(Extended Unix Code)存储;
        比如‘啊’字位于16区的1号位,存储的时,编号是:176,161; 转换为16进制表示就是B0,A1; (注:这里A1是高字节)
        详细信息请参阅中华人民共和国 国家标准《信息交换用汉字编码字符集--基本集》
        
    GB2312字符集
        它通行于大陆,新加波;虽然收录了一些日文,俄文字符,但没有收录少数民族比如藏族语言中的字符;
        还有很多古文和生僻字也没收录;这是它的缺陷;
    
    BIG-5字符集
        它是通行于港台的繁体字符集;共收录13060个字符从A140开始;高字节编码范围是0x81-0xFE,
        低字节编码范围是0x40-0x7E和0xA1-0xFE; 0x8140-0xA0FE是保留区域,用于用户造字区。
    
    GBK 是一个局部通用的字符集,该规范收录了ISO 10646.1中的全部 CJK 字符集,并有所补充;
        (CJK Unified Ideographs中日韩统一表意文字它  是《GB2312-80》、《BIG5》等字符集的超集)
        GBK的整体编码范围是为0x8140-0xFEFE,不包括低字节是0x7F的组合。
        高字节范围是0X81-0xFE,低字节范围是0x40-0x7E和0x80-0xFE。 
    
        GBK和GB2312都是双字节等宽编码,如果算上和ASCII兼容所支持的单字节,可以理解为是单字节和双字节混合的变长编码
    
    GB18030 字符集收录了所有Unicode3.1中的字符,包括中国少数民族字符,GBK不支持的韩文字符等等,也可以说是世界
        大多民族的文字符号都被收录在内。GB18030编码是变长编码,有单字节、双字节和四字节三种方式。   
        单字节编码范围是0x00-0x7F,完全等同ASCII;
        双字节编码的范围和GBK相同,高字节是0x81-0xFE,低字节的编码范围是0x40-0x7E和0x80-FE;
        四字节编码中第一、三字节的编码范围是0x81-0xFE,二、四字节是0x30-0x39。   
    
    
    ANSI 编码:
        它是不同系统下各种编码的称谓:没有新增加编码字符集;百度百科上的定义:
        不同的国家和地区制定了不同的标准,由此产生了 GB2312, BIG5, JIS 等各自的编码标准。
        这些使用 2 个字节来代表一个字符的各种汉字延伸编码方式,称为 ANSI 编码。
        比如:在简体中文系统下,ANSI 编码代表 GB2312 编码,在日文操作系统下,ANSI 编码代表 JIS 编码;
        对于ANSI编码而言,0x00~0x7F之间的字符,依旧是1个字节代表1个字符。
    
    代码页:
        代码页是字符集编码的别名;不过是给字符集编码编了个号;
        代码页分单字节代码页和多字节代码页;扩展ASCII字符在单字节代码页下都是可见的;
      437代码页表示美国英语MS-DOS编码
        现在936代码页是GBK编码的别名,但又很细微的差别;(以前936代码页是gb2312)
        根据微软资料,GBK是对GB2312-80的扩展,也就是CP936字码表 (Code Page 936)的扩展
        (之前CP936和GB 2312-80一模一样),
        GBK自身并非国家标准,只是曾由国家技术监督局标准化司、电子工业部科技与质量监督司公布为“技术规范指导性文件”。
        原始GB13000一直未被业界采用,后续国家标准GB18030技术上兼容GBK而非GB13000。
    
    
    unicode(统一码)编码系统:
        可分为编码方式和实现方式两个层次。
        目前实际应用的统一码版本对应于UCS-2,使用16位的编码空间。也就是每个字符占用2个字节。
        这样理论上一共最多可以表示216(即65536)个字符。基本满足各种语言的使用。实际上目前版本的统一码并未完全使用
        这16位编码,而是保留了大量空间以作为特殊使用或将来扩展。
    
        最新(但未实际广泛使用)的统一码版本定义了16个辅助平面,两者合起来至少需要占据21位的编码空间,比3字节略少。
        但事实上辅助平面字符仍然占用4字节编码空间,与UCS-4保持一致。未来版本会扩充到ISO 10646-1实现级别3,
        即涵盖UCS-4的所有字符。UCS-4是一个更大的尚未填充完全的31位字符集,加上恒为0的首位,共需占据32位,即4字节。
        理论上最多能表示2^31个字符,完全可以涵盖一切语言所用的符号。
        注:
            通用字符集Universal Character Set,UCS,即是由ISO制定的ISO 10646
            (或称ISO/IEC 10646)标准所定义的标准字符集。 采用4byte编码.
    
    
        基本多文种平面的字符的编码为U+hhhh,其中每个h 代表一个十六进制数字,与UCS-2编码完全相同。
        而其对应的4字节UCS-4编码后两个字节一致,前两个字节则所有位均为0。
    
        unicode和UCS只是分配整数给字符的编码表;位字符定义了顺序;
        utf-8, utf-16 是对unicode的编码方法存储的压缩实现;
        就像gb2312区位码只定义了94区94位,存储实现的时候为了兼容ASCII给每个字符+160;知识没有压缩数据;
    Unicode和UTF-8之间的转换关系表
    UCS-4编码UTF-8字节流
    U+00000000 – U+0000007F 0xxxxxxx
    U+00000080 – U+000007FF 110xxxxx 10xxxxxx
    U+00000800 – U+0000FFFF 1110xxxx 10xxxxxx 10xxxxxx
    U+00010000 – U+001FFFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
    U+00200000 – U+03FFFFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
    U+04000000 – U+7FFFFFFF 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

    参考
    http://zh.wikipedia.org/wiki/Unicode             http://blog.donews.com/holen/archive/2004/11/30/188182.aspx

    平时我们使用windows时,记事本->另存为->“保存”-> “编码”的下拉菜单 中有4个选项,

    分别是ANSI, Unicode, Unicode big edian, UTF-8; 稍解释下:
    windows XP以后的系统ANSI在简体中文下对应的是GBK编码(请不要贸然否定这句话,我做过考证)
    Unicode 统一编码,为了数据共享,
    big edian, 大端字节序(高字节对应低位数据),windows默认是小端存储(低字节对应低位数据)

    View Code
    big endian表示大端存储(高字节存储低位数据),intel模式是小端little endian存储(高字节存储高位数据),比如gb2312编码规定是第1字节存放区码,第2存放位码;""的区码是16, 位码是1;那么用小端方式就是高字节对应1, 低字节对应16了;
    什么叫高字节,低字节?
    通俗讲:打开记事本,输入0123456,0在内存中对应的就是低字节,1在内存中对应的就是高字节;

    UTF-8 Unicode编码的一种实现,节省了存储空间,相当于压缩了unicode编码的压缩方法;

    utf-8与unicode的互转:

    在实际生活中,经常遇到utf-8, ansi,unicode编码的转换;我们只需要掌握utf-8和unicode的互转,剩下的就很easy,后面你会体会到的

    对于gbk字符集来说,我们只需关心u+00000000~u+0000ffff的范围就行了;其他的范围很少能遇到;
    从Unicode 到utf8的转换关系表,我们得到下面的小端存储方式, Unicode 转 utf8的 伪代码:

    if(数据的高字节==0, 低字节 < 0x80)
        输出 低字节;
    else if(数据的高字节 < 0x08,低字节 >= 0x80)
        输出 B(1000 0000)|(数据的0~5位), B(1100 0000)|B(数据的6~11位) 
    else
        输出 B(1000 0000)|B(数据的0~5位), B(1000 0000)|B(数据的6~11位), B(1110 0000)|B(数据的12~15)
    --------------------------
    if(data < 0x0080)
        printf("%c%c", data,0);
    else if(data >= 0x0080 && data < 0x08ff)
        printf("%c%c",0x80 | data&0x3F, 0xC0 | (data&0X0FC0)>>6);
    else
        printf("%c%c", 0x80|data&0x3F, 0x80|(data&0x0FC0)>>6, 0xE0|(data&0xF000)>>12);

     utf8转Unicode的伪代码:

    if (d[i]<0x80)
        print d;
    else if (d[i+1] > 0xC0)
        x=(d[i+1]&0x1F)<<6|d[i]&0x3F;
        printf x&0x00FF , (x&0xFF00)>>8;
    else 
        x = (d[i+2]&0x0F)<<12|(d[i+1]&0x3F)<<6|d[i]&0x3F;
        printf x&0x00FF , (x&0xFF00)>>8;

    对于utf8和gbk的互转,通过unicode这个桥梁实现;
    gbk如何转unicode? 使用cmd/u&type系统调用;

    unicode 如何转gbk? 使用系统调用type(默认情况/u开关时关闭的);

  • 相关阅读:
    Oracle创建用户并赋予权限
    Oracle查询表空间使用情况
    Oracle更改数据库文件大小、实时增加文件容量
    Oracle查询数据中占用空间最大的表
    Oracle存储包存储及案例
    Oracle包Package调用Package
    Oracle存储过程Procedure语法及案例
    Oracle存储过程function语法及案例
    Oracle常用语法
    Oracle游标循环更新数据案例
  • 原文地址:https://www.cnblogs.com/mathzzz/p/2593493.html
Copyright © 2011-2022 走看看