搜索

查看: 3134|回复: 11

[JavaScript] JavaScript开发中需要搞懂的字符编码总结

[复制链接]
发表于 2023-5-4 11:50:55 | 显示全部楼层 |阅读模式
Editor 2023-5-4 11:50:55 3134 11 看全部
目录
  • 字符集和字符编码
  • ASCII
  • 字符集的发展历史
  • Unicode
  • UTF-8
  • UTF-16
  • 比较
  • 前端开发中的编码
  • 字符串长度计算
  • 组合字符的长度
  • 多码元字符操作
  • 正则中的 u 修饰符
  • 转义字符
  • 常用API
  • 处理码点和字符
  • TextEncoder
  • String.prototype.normalize()
  • URL的UTF8编解码
    字符集和字符编码
    字符集就是字符的集合,如常见的 ASCII字符集,GB2312字符集,Unicode字符集等。这些不同字符集之间最大的区别是所包含的字符数量的不同。
    字符编码则代表字符集的实际编码规则,是用于计算机解析字符的,如 GB2312,GBK,UTF-8 等。字符编码的本质就是如何使用二进制字节来表示字符的问题。
    字符集和编码是一对多的关系,同一字符集可能有多种字符编码,如Unicode字符集就有 UTF-8,UTF-16 等。
    在前端开发中,Javascript程序是使用Unicode字符集,Javascript源码文本通常是基于UTF-8编码。
    但JS代码中的字符串类型是UTF-16编码的,这也是为什么会碰到api接口返回字符串在前端出现乱码,因为多数后台服务都使用utf-8编码,前后编码方式不一致。
    说起字符集的发展历程,可以总结为一句话:几乎都是对ASCII字符集的扩展。

    ASCII
    我们知道,计算机是使用二进制来处理信息的。
    其中,每一个二进制位(bit)有 0和1 两种状态。一个字节(byte)则有8个二进制位,可以有256种状态。
    而ASCII就是基于拉丁字母、主要用于显示英文的一种单字节字符集,它的编码和字符是一一对应的,因为它就是使用一个字节8个二进制位来表示,不会超过256个字符。
    标准的ASCII字符总计有128个字符(2^7),其中前面32个控制字符,后面96个是可打印字符,包括常用的大小写字母数字标点符号等。因为只占用了一个字节的后7位,那字节的最高位一般设置为0。
    'a'.charCodeAt() // 97
    'A'.charCodeAt() // 65
    '9'.charCodeAt() // 57
    '.'.charCodeAt() // 46
    如上,每个字符会对应一个编码(使用数字标识),总共会从0-128。完整的ASCII码表,网上很容易找到。
    通过ASCII码表,我们发现,小写字母并没有和大写字母挨着排序?
    这是为了方便大小写之间的转换, A 排在 65(64 + 1) 位,而 a 排在 97(64 + 32 + 1) 位。
    65 ^ 32 = 97
    // A ^ 32 = a

    字符集的发展历史
    ASCII是几乎所有字符集的基础。
    标准的ASCII码最多只能标识128个字符,欧美国家可以很好的使用,但其他国家的字符变多,自然就不够用了。
    这个时候,最高位就开始被惦记上,通过扩展ASCII码的最高位,又能满足用于特殊符号的一些国家的需求,这种就是扩展ASCII码。
    但是亚非拉更多非拉丁语系的国家,字符成千上万,只能使用新的方式。
    如中文,就又进行了扩展,小于127的字符的意义与标准ASCII码相同,当需要标识汉字时,使用2个字节,每个字节都大于127。这种多字节字符集即GB2312,后续因为不断的扩展,如繁体字和各种符号,甚至少数民族的语言符号等等,又使用了包括GBK等不同字符集。
    因此,很多国家都制定了自己的编码字符集,基本都是在ASCII的基础上进行的。
    各字符集虽然都能够兼容标准ASCII码,但在使用交流上的不便是显而易见的,乱码也是随处可见。为了解决这种各自为战的问题,Unicode字符集就诞生了。

    Unicode
    Unicode是国际组织制定的,用于收纳世界上所有文字和符号的字符集方案。
    前128个字符同ASCII一样,进行扩充后,使用数字0-0x10FFFF来映射这些字符,最多可以有1114112个字符。目前仍然只使用了其中的一小部分。
    Unicode一般使用两个字节来表示一个字符。
    码点
  • Unicode 规定了每个字符的数字编号,这个编号被称为 码点(code point)。
  • 码点以 U+hex 的形式表示,U+是代表Unicode的前缀,而 hex 是一个16进制数。取值范围是从 U+0000 到 U+10FFFF。
  • 每个码点对应一个字符,绝大部分的常见字符在最前面的 65536 个字符,范围是 U+0000到U+FFFF。
  • 一般汉字的码点区间为 U+2E80 - U+9FFF。
    字符平面
  • 目前的Unicode分成了17个编组,也称平面,每个平面有65536个码点。
  • 第一个平面是基本多语言平面,范围:U+0000 - U+FFFF,多数常见字符都在该区间。
  • 其他平面则为辅助平面,范围:U+10000 到 U+10FFFF,如我们在网上常见 Emoji 表情。
    码元
  • 码元(Code Unit)可以理解为对码点进行编码时的最小基本单元,码元是一个整体。而字符编码的作用就是将Unicode码点转换成码元序列。
  • Unicode常用的编码方式有 UTF-8 、UTF-16 和 UTF-32,UTF是Unicode TransferFormat的缩写。
  • UTF-8是8位的单字节码元,UTF-16是16位的双字节码元,UTF-32是32位的四字节码元。
    编码方式码元编码后字节数
    UTF-88位1-4字节
    UTF-1616位2字节或者4字节
    UTF-3232位4字节

    另外,为什么总看到使用十六进制数据来表示如码点等各种数据呢?
    因为,两位的十六进制正好等于一个字节8位,0xff = 0b11111111。

    UTF-8
    UTF-8是一种可变长度的字符编码方式。目前是使用 1 到 4 个字节来编码字符。
    是互联网时代应用最广的一种编码方式,前端接触的相对最多。
    需要注意的是:汉字一般占3个字节,表情符号一般占4个字节。
    UTF-8的编码规则:
  • 1个字节的字符,第一位为0,后7位为码点,与ASCII相同。
  • n个字节的字符,第一个字节前面 n 位都是1,n+1位是0,可据此判断有几个字节。后面的几个字节都是 10 为开头2位。
    这里规定的都是前缀,对于字符的码点,需要进行截取后依次放入除前缀外的其他位,所以UTF-8又被称为前缀码。
    格式如下表:
    字节数码点位数码点范围编码方式
    17U+0000~U+007F0×××××××
    211U+0080~U+07FF110××××× 10××××××
    316U+0800~U+FFFF1110×××× 10×××××× 10××××××
    421U+10000~U+10FFFF11110××× 10×××××× 10×××××× 10××××××

    通过上表的编码规则,我们就可以进行各种转换了。
    下面我们以一个中文字符的编码转换为例,如汉字 '好':
    '好'的Unicode码点:'好'.codePointAt() \\ 22909,结果是22909
    22909在UTF-8的3字节数的编码区间 U+0800 (2048) ~ U+FFFF (65535)
    22909的二进制值:101100101111101,有15位
    而3字节数的编码需要16位,前面补0,根据表中规则分成3组:0101 100101 111101
    依次填入对应的前缀:11100101 10100101 10111101,得到3个字节
    将得到的三个字节转成十六进制数据:E5 A5 BD,所以汉字 '好' 的UTF-8就是:E5 A5 BD
    我们使用 encodeURI 进行验证————encodeURI函数支持将中文进行 UTF-8 编码:
    encodeURI('好') // '%E5%A5%BD'
    去除百分号,结果正好一致。

    UTF-16
    UTF-16的编码方式:基本平面的字符占用 2 个字节(U+0000到U+FFFF),辅助平面的字符占用 4 个字节(U+010000到U+10FFFF)。
    也就是说,UTF-16的编码长度要么是2个字节要么是4个字节。当为2字节时,则实际上是与Unicode相同。
    并且还有个原则,在Unicode基本多语言平面内,从U+D800到U+DFFF之间的码点区间是不对应字符的。而UTF-16需要利用这块码位来对辅助平面的字符进行编码。
    它的具体规则:
    码点小于U+FFFF,基本字符,不需处理,直接使用,占两个字节。
    否则,拆分成两个码元,四个字节,cp表示码点:
    低位——((cp - 65536) / 1024) + 0xD800,值范围是 0xD800~0xDBFF;
    高位——((cp - 65536) % 1024) + 0xDC00,值范围是 0xDC00~0xDFFF。
    看下面的示例:
    1.汉字 '好','好'.codePointAt() // 22909,码点小于U+FFFF,直接进行十六进制转换:579D。
    2.表情符号 '
  • 回复

    使用道具 举报

    发表于 2023-6-28 23:45:40 | 显示全部楼层
    小妖花满楼满fx 2023-6-28 23:45:40 看全部
    感谢楼主的无私分享!要想知鸟论坛好 就靠你我他
    回复

    使用道具 举报

    发表于 2023-6-29 22:41:46 | 显示全部楼层
    哈哈SE7 2023-6-29 22:41:46 看全部
    楼主,大恩不言谢了!知鸟论坛是最棒的!
    回复

    使用道具 举报

    发表于 2023-6-30 00:26:41 | 显示全部楼层
    永远爱你冰塘 2023-6-30 00:26:41 看全部
    这东西我收了!谢谢楼主!知鸟论坛真好!
    回复

    使用道具 举报

    发表于 2023-6-30 08:52:12 | 显示全部楼层
    计划你大爷计j 2023-6-30 08:52:12 看全部
    这个帖子不回对不起自己!我想我是一天也不能离开知鸟论坛
    回复

    使用道具 举报

    发表于 2023-6-30 19:53:50 | 显示全部楼层
    123456809 2023-6-30 19:53:50 看全部
    既然你诚信诚意的推荐了,那我就勉为其难的看看吧!知鸟论坛不走平凡路。
    回复

    使用道具 举报

    发表于 2023-7-3 10:31:20 | 显示全部楼层
    知足常乐77 2023-7-3 10:31:20 看全部
    感谢楼主的无私分享!要想知鸟论坛好 就靠你我他
    回复

    使用道具 举报

    发表于 2023-7-4 14:55:33 | 显示全部楼层
    风来时狂放 2023-7-4 14:55:33 看全部
    楼主发贴辛苦了,谢谢楼主分享!我觉得知鸟论坛是注册对了!
    回复

    使用道具 举报

    发表于 2023-7-6 20:17:57 | 显示全部楼层
    丁侦球 2023-7-6 20:17:57 看全部
    我看不错噢 谢谢楼主!知鸟论坛越来越好!
    回复

    使用道具 举报

    发表于 2023-7-6 20:24:51 | 显示全部楼层
    素色流年783 2023-7-6 20:24:51 看全部
    楼主,大恩不言谢了!知鸟论坛是最棒的!
    回复

    使用道具 举报

    • 您可能感兴趣
    点击右侧快捷回复 【请勿灌水】
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则 返回列表

    RSS订阅| SiteMap| 小黑屋| 知鸟论坛
    联系邮箱E-mail:zniao@foxmail.com
    快速回复 返回顶部 返回列表