美文网首页
搞定编码格式问题

搞定编码格式问题

作者: shuaiutopia | 来源:发表于2019-06-01 16:16 被阅读0次

    Unicodeutf-8

    以下文章来自知乎回答

    Unicode 是「字符集」
    UTF-8 是「编码规则」

    其中:

    字符集:为每一个「字符」分配一个唯一的 ID(学名为码位 / 码点 / Code Point)
    编码规则:将「码位」转换为字节序列的规则(编码/解码 可以理解为 加密/解密 的过程)

    广义的 Unicode 是一个标准,定义了一个字符集以及一系列的编码规则,即 Unicode 字符集和 UTF-8、UTF-16、UTF-32 等等编码……
    Unicode 字符集为每一个字符分配一个码位,例如「知」的码位是 30693,记作 U+77E5(30693 的十六进制为 0x77E5)。
    UTF-8 顾名思义,是一套以 8 位为一个编码单位的可变长编码。会将一个码位编码为 1 到 4 个字节:

        U+ 0000 ~ U+ 007F : 0XXXXXXX   
        U+ 0080 ~ U+ 07FF : 110XXXXX 10XXXXXX   
        U+ 0800 ~ U+ FFFF : 1110XXXX 10XXXXXX 10XXXXXX   
        U+10000 ~ U+1FFFF : 11110XXX 10XXXXXX 10XXXXXX 10XXXXXX   
    

    根据上表中的编码规则,之前的「知」字的码位 U+77E5 属于第三行的范围:

        7    7    E    5         
        0111 0111 1110 0101  二进制的 77E5 
        --------------------------     
        1110XXXX 10XXXXXX 10XXXXXX 模版(上表第三行,X的个数为 4 6 6)即讲77E5的 0111011111100101按长度4 6 6 截取
        0111   011111   100101 二进制的 77E5 (unicode统一用两个字节byte即16位bit来表示所有字符)
        11100111 10011111 10100101 代入模版    
          E 7       9 F     A 5 
          
    # 帅的 Unicode编码16进制为 5E05      
        5    E    0    5         
        0101 1110 0000 0101  二进制的 5E05
        --------------------------     
        1110XXXX 10XXXXXX 10XXXXXX 模版(上表第三行,X的个数为 4 6 6)即讲77E5的 0111011111100101按长度4 6 6 截取
        0101   111000   000101 二进制的 77E5 (unicode统一用两个字节byte即16位bit来表示所有字符)
        11100101 10111000 10000101 代入模版    
          E 5       B 8     8 5 
    

    这就是将 U+77E5 按照 UTF-8 编码为字节序列 E79FA5 的过程。反之亦然。

    unicod与utf-8

    一个叫 ISO(国际标谁化组织)的国际组织决定着手解决各地区编码混乱的问题。他们采用的方法很简单:废了所有的地区性编码方案,重新搞一个包括了地球上所有文化、所有字母和符号 的编码!他们打算叫它”Universal Multiple-Octet Coded Character Set”,简称 UCS, 俗称 “unicode“。

    unicode开始制订时,计算机的存储器容量极大地发展了,空间再也不成为问题了。于是 ISO 就直接规定必须用两个字节,也就是16位来统一表示所有的字符,对于ASCII里的那些“半角”字符,unicode包持其原编码不变,只是将其长度由原来的8位扩展为16位,而其他文化和语言的字符则全部重新统一编码。由于”半角”英文符号只需要用到低8位,所以其高8位永远是0,因此这种大气的方案在保存英文文本时会多浪费一倍的空间。

    这时候,从旧社会里走过来的程序员开始发现一个奇怪的现象:他们的 strlen 函数靠不住了,一个汉字不再是相当于两个字符了,而是一个!是的,从unicode开始,无论是半角的英文字母,还是全角的汉字,它们都是统一的”一个字符“!同时,也都是统一的”两个字节“,请注意”字符”和”字节”两个术语的不同,“字节”是一个8位的物理存贮单元,而“字符”则是一个文化相关的符号。在unicode中,一个字符就是两个字节。一个汉字算两个英文字符的时代已经快过去了。

    unicode同样也不完美,这里就有两个的问题,一个是,如何才能区别unicode和ascii?计算机怎么知道三个字节表示一个符号,而不是分别表示三个符号呢?第二个问题是,我们已经知道,英文字母只用一个字节表示就够了,如果unicode统一规定,每个符号用三个或四个字节表示,那么每个英文字母前都必然有二到三个字节是0,这对于存储空间来说是极大的浪费,文本文件的大小会因此大出二三倍,这是难以接受的。

    unicode在很长一段时间内无法推广,直到互联网的出现,为解决unicode如何在网络上传输的问题,于是面向传输的众多 UTF(UCS Transfer Format)标准出现了,顾名思义,UTF-8就是每次8个位传输数据,而UTF-16就是每次16个位。UTF-8就是在互联网上使用最广的一种unicode的实现方式,这是为传输而设计的编码,并使编码无国界,这样就可以显示全世界上所有文化的字符了。UTF-8最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度,当字符在ASCII码的范围时,就用一个字节表示,保留了ASCII字符一个字节的编码做为它的一部分,注意的是unicode一个中文字符占2个字节,而UTF-8一个中文字符占3个字节)。从unicode到utf-8并不是直接的对应,而是要过一些算法和规则来转换。

    Unicode符号范围       |    UTF-8编码方式  
    (十六进制 )           |   (二进制,1-4个字节,每个字节8位) 这里的二进制再用两位的16进制表示,见上面  
    —————————————————————–   
    0000 0000 - 0000 007F | 0xxxxxxx                  //这里007F刚好就是127,是ascII码包括的的所有字符
    0000 0080 - 0000 07FF | 110xxxxx 10xxxxxx  
    0000 0800 - 0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx  
    0001 0000 - 0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
    

    base64编码

    Base64 是网络上最常见的用于传输 8Bit 字节码的编码方式之一,Base64就是一种基于 64 个可打印字符来表示二进制数据的方法。Base64 编码是从二进制到字符的过程.

    base64对照.jpg

    普通字符串转 base64

    首先清晰一个概念: 内存1个字节占8位即 1byte = 8bit;
    Base64 要求把每三个8Bit 的字节转换为四个6Bit(为什么是 bBit呢,因为6位二进制最大 111111 等于 63,刚好 64 个字符) 的字节(3*8 = 4*6 = 24),然后把6Bit再添两位高位0,组成四个 8Bit 的字节,也就是说,转换后的字符串理论上将要比原来的长 1/3

    转换的时候,将三个byte的数据,先后放入一个24bit的缓冲区中,先来的byte占高位。数据不足3byte的话,缓冲区中剩下的Bit0补足。如果最后剩下两个输入数据,在编码结果后加1=;如果最后剩下一个输入数据,编码结果后加2=;如果没有剩下任何数据,就什么都不要加,这样才可以保证资料还原的正确性。

    转码过程例子:
    3*8=4*6
    内存1个字节占8位
    转前: s 1 3
    先转成ascii:对应 115 49 51
    2进制: 01110011 00110001 00110011
    6个一组(4组) 011100110011000100110011
    然后才有后面的 011100 110011 000100 110011
    然后计算机是8位8位的存数 6不够,自动就补两个高位0了
    所有有了 高位补0
    科学计算器输入 00011100 00110011 00000100 00110011
    得到 28 51 4 51
    查对下照表 c z E z
    
    转前: a
    先转成ascii:           97(十进制,和用utf-8表示的16进制的 61是一样的)
    2进制:                01100001
    数据不足,补足(3*8)        01100001 00000000 00000000
    6个一组(4组)        011000 010000 000000 000000
    高位补0凑够8位        00011000 00010000 00000000 00000000
    转十进制得到          24 16
    查base64对照表              Y Q
    最后补两个=得到            YQ==
    如果最后剩下两个输入数据,在编码结果后加`1`个`=`;如果最后剩下一个输入数据,编码结果后加`2`个`=`
    
    转前: 帅
    先转成utf-8:           e5 b8 85      ##可通过let buf = Buffer.from("帅")获得utf-8编码,为16进制
    2进制:                11100101 10111000 10000101
    6个一组(4组)        111001 011011 100010 000101
    高位补0凑够8位        00111001 00011011 00100010 00000101
    转十进制得到          57 27 34 5
    查base64对照表              5 b i F       ## 可通过buf.toString("base64")来验证
    

    其他base64相关

    url地址要先转码后再转base64.
    点击查看base64的理解
    转换方法;

    !function(W){
      W.Base64 = {
         utf8ToBase64:function (str){
           return btoa(unescape(encodeURIComponent(str)));
         },
         base64ToUtf8: function(str){
            return decodeURIComponent(escape(atob(str)));
          }
      }
    }(window);
    

    相关文章

      网友评论

          本文标题:搞定编码格式问题

          本文链接:https://www.haomeiwen.com/subject/okjatctx.html