美文网首页
字符串转 UTF-8 二进制

字符串转 UTF-8 二进制

作者: 嚼不烂的口香糖 | 来源:发表于2020-06-02 10:41 被阅读0次

首先了解几个简单的知识点:

  • unicode 是一个字符集,它规定一个字符对应哪一个二进制
  • utf-8 是 unicode字符集 的编码方式,即表现形式之一

了解一下 UTF-8

UTF-8 是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。
编码规则:

  1. 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。
  2. 对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。

编码规则表,字母x表示可用编码的位

Unicode符号范围(十六进制) UTF-8编码方式(二进制)
0000 0000-0000 007F 0xxxxxxx
0000 0080-0000 07FF 110xxxxx 10xxxxxx
0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

根据上表,解读 UTF-8 编码非常简单。如果一个字节的第一位是0,则这个字节单独就是一个字符;如果第一位是1,则连续有多少个1,就表示当前字符占用多少个字节。


//01100001
const str = '被讨厌的勇气';
//str2bin(str);
console.log(str2bin(str, true));

/**
 * 字符串转 utf-8 二进制
 *
 * UTF-8 是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。
 * 两条规则:
 * 1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。
 * 2)对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。
 * @param str
 */
function str2bin(str, byByte = false) {
    let str_arr = new Array(4);
    let unicode_num, bin_arr = new Array();
    for (let i = 0; i < str.length; i++) {
        str_arr.fill('');
        unicode_num = str.charCodeAt(i);

        // 十六进制范围:00000000 ~ 0000007F
        // 二进制范围:0 ~ 2^7-1
        // 格式:0xxxxxxx
        if (unicode_num < 128) {
            str_arr[0] = pad_zero(unicode_num.toString(2), 8);
        }
        // 00000080 ~ 000007FF
        // 2^7 ~ 2^11-1
        // 格式:110xxxxx 10xxxxxx
        else if (unicode_num >= 128 && unicode_num < 2048) {
            // 第一字节 110xxxxx
            //1. 右移6位, 即去掉右边6位
            //2. 填充到 110xxxxx, 即设置7位和6位为1, 1100000 = 2^7 + 2^6 = 128 + 64 = 192
            str_arr[0] = ((unicode_num >> 6) | 192).toString(2);
            // 第二字节 10xxxxxx
            //1. 先取后6位, 63 = 64 - 1 = 2^6 - 1 = 1000000 - 1 = 111111
            //2. 填充到 10xxxxxx 中, 1000000 = 2^7 = 128, a | 128 即设置a的7位为1,其他保持不变
            str_arr[1] = ((unicode_num & 63) | 128).toString(2);
        }
        // 00000800 ~ 0000FFFF
        // 2^11 ~ 2^16-1
        // 格式:1110xxxx 10xxxxxx 10xxxxxx
        else if (unicode_num >= 128 && unicode_num < 65536) {
            // 第一字节
            // 1.右移12位
            // 2.填充到 1110xxxx, 11100000 = 2^7 + 2^6 + 2^5 = 224
            str_arr[0] = ((unicode_num >> 12) | 224).toString(2);

            // 第二字节 - 取中间6位
            // 1.右移6位
            // 2.取后6位
            // 3.填充到 10xxxxxx
            str_arr[1] = (((unicode_num >> 6) & 63) | 128).toString(2);

            // 第三字节 - 取后6位
            str_arr[2] = ((unicode_num & 63) | 128).toString(2);
        }
        // 00010000 ~ 0010FFFF
        // 2^16 ~ (2^17 + 2^16 - 1)
        // 65536 ~ 196607
        // 格式:11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
        else {
            // 第一字节
            // 1.右移18位
            // 2.填充到 11110xxx, 11110000 = 2^7 + 2^6 + 2^5 + 2^4 = 240
            str_arr[0] = ((unicode_num >> 18) | 240).toString(2);

            str_arr[1] = (((unicode_num >> 12) & 63) | 128).toString(2);
            str_arr[2] = (((unicode_num >> 6) & 63) | 128).toString(2);
            str_arr[3] = ((unicode_num & 63) | 128).toString(2);

        }

        // 按字节返回 或 按字符返回
        if (byByte) {
            bin_arr = bin_arr.concat(str_arr.filter(item => {
                return item.length > 0;
            }));
        } else {
            bin_arr.push(str_arr.join(''));
        }
    }

    return bin_arr;
}

/**
 * 填充0
 * @param input
 * @param pad_len
 * @param pad_type 0:左填充 1:右填充
 * @returns {number|string|number}
 */
function pad_zero(input, pad_len, pad_type = 0) {
    if (typeof input == 'number') {
        input += '';
    }

    let str_len = input.length;
    if (str_len >= pad_len) {
        return input;
    }

    for (let i = 0; i < pad_len - str_len; i++) {
        if (pad_type) {
            input += '0';
        } else {
            input = '0' + input;
        }
    }

    return input;
}

参考文档

阮一峰-字符编码笔记

相关文章

网友评论

      本文标题:字符串转 UTF-8 二进制

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