也谈Unicode和UTF-8

最近在学习字符集相关的内容,遂以此文进行记录。

Unicode

  1. 起源

    大家都知道计算机起源于美国,而美国人一开始通信用的是ASCII字符,其包含所有大小写字母和常用的英文标点符号,足够美国人使用。后来计算机在其他国家普及,由于语种多样性ASCII字符不再满足需要。于是便有了欧洲的ISO 8859以及中文的GBK编码。但这样就有一个问题,美国的计算机接受到来自中国的电子邮件后无法正常显示内容。为了解决这种各国编码规范不统一的问题,The Unicode Consortium指定了Unicode(也叫国际码)标准。

  2. 编码方式

    当前的Unicode使用16位的编码空间,每个字符占2字节,理论上最多可表示65536个字符。基本满足各种语言的使用。基本多文种平面的字符的编码为U+hhhh,每个h代表一个十六进制的数字。

UTF-8

  1. 起源

    在实际传输过程中,由于不同系统平台的设计不确定性,以及出于节省空间的目的,对 Unicode 编码的实现方式有所不同。Unicode 的实现方式称为 Unicode转换格式(Unicode Transformation Format,简称为 UTF)。而UTF-8就是8位的unicode转换格式。

  2. 编码方式

    以8位为单元对UCS进行编码,每个使用UTF-8存储的字符,除了第一个自己外,其余字节的头两个比特都是以“10”开始,使文字处理器能够较快的找出每个字符的开始位置。为了兼容ASCII,UTF-8选择以可变长度存储Unicode。转换关系图如下:

  3. Unicode转UTF-8

    已知“严”的unicode是4E25(100111000100101), 根据上表,可以发现4E25处在第三行的
    范围内(U+0800-U+FFFF), 因此“严”的UTF-8编码需要三个字节,即格式是
    “1110xxxx 10xxxxxx 10xxxxxx”。 然后, 从“严”的最后一个二进制位开始,依次从后向前
    填入格式中的x,多出的位补0。 这样就得到了“严”的UTF-8编码是”11100100 10111000
    10100101”, 转换成十六进制就是E4B8A5。

    附JavaScript实现代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    function encodeUTF8(str) {
    let code = parseInt(str.codePointAt().toString(16), 16);
    let bCodes = str.codePointAt().toString(2).split('');
    let byte, template, result = '', temp;
    if(code<parseInt('007F', 16)) {
    template = '0xxxxxxx';
    byte = 1;
    }else if(code<parseInt('07FF', 16)) {
    template = '110xxxxx10xxxxxx'
    byte = 2;
    }else if(code<parseInt('FFFF', 16)) {
    template = '1110xxxx10xxxxxx10xxxxxx'
    byte = 3;
    }else if(code<parseInt('1FFFFF', 16)) {
    template = '1110xxxx10xxxxxx10xxxxxx'
    byte = 4;
    }else if(code<parseInt('1FFFFF', 16)) {
    template = '11110xxx10xxxxxx10xxxxxx10xxxxxx'
    byte = 5;
    }else if(code<parseInt('3FFFFFF', 16)) {
    template = '111110xx10xxxxxx10xxxxxx10xxxxxx10xxxxxx'
    byte = 6;
    }else if(code<parseInt('7FFFFFFF', 16)) {
    template = '1111110x10xxxxxx10xxxxxx10xxxxxx10xxxxxx10xxxxxx'
    byte = 7;
    }
    template = template.split('').reverse().map(t => {
    if(t == 'x') {
    if(bCodes.length > 0) {
    return bCodes.pop();
    }else{
    return 0;
    }
    }else{
    return t;
    }
    })
    temp = parseInt(template.reverse().join(''), 2).toString(16)
    let len = temp.length / byte
    for(let i=1;i<=byte;i++) {
    result += '\\x' + temp.slice((i-1)*len, i*len)
    }
    return result
    }

    let encoding = str => str.split('').map(s => encodeUTF8(s)).join('')

    console.log(encoding('严厉'))
打赏
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • © 2019-2021 musi

请我喝杯咖啡吧~

支付宝
微信