每日 30 秒 ⏱ 字符编码排雷录

简介

字符编码、字符长度错误、截取字符错误、UTF八、Unicodejavascript

计算机重重底层之下都是由 0 和 1 组合,可是你知道他们是怎么一步步变成字符串的嘛?在咱们现实生活中最多见的例子能够经过 wo 在新华字典中找到 这个字。一样计算机经过 0 和 1 组合在 字典 中查找到对应的字符,那 字典 内容是什么呢?html

起源

计算机诞生于 美国 它的使用者大多数使用英文,美国国家标准学会 便制定了这本字典包括了 26个大写英文字母26个小写英文字母10个阿拉伯数字等总共 256 个字符的 ASCII 字符集。前端

混乱

ASCII 用二进制来表示就是 0000 00001111 1111 被用得满满当当,汉字就没有地方能够放得下了这下怎么办?正所谓江山大有人才出,国标编码 GB 系列出现了,其中最耳熟能详的就是 GB2312java

那么问题来了世界拥有 25003500 种语言,有文字的语言有 930 种。你能想象你在浏览不一样语言界面的时候,须要本身不断的去切换 字典 而且 每次切换查找不到的字符就会乱码出现。git

统一

书同文,车同轨,行同伦。es6

上面这句话歌颂了秦始王具备跨时代意义的成就,可是现实世界中统一语言显得不可能。那咱们可否换个思路解决这个问题呢?先思考一个问题:“把大象放入冰箱须要几步”,答案你们都知道“打开,装进去,关上”。那统一字符怎么办呢?那就是建立一个足够大的字典把全部的字符都放进去。github

万国码

Unicode 万国码 轰隆一声诞生了,顾名思义统一了全世界的全部文字编码能够到 Unicode Consortiumcodepoints 中查看,对应的实现有UTF八、UTF16 、UTF-32。数据库

可变长度字符编码

UTF八、UTF1六、UTF-32最大区别在于对应多少字节的数据,越大能存储的字符也就越多。其中 UTF-8 就是在互联网上使用最广的一种 Unicode 的实现方式,也就是如今 html 中最常看到的 <meta charset="UTF-8"> 所声明字符集。后端

UTF 最大的特色在于可变长的字节,例如 UTF8 能够是 1到4个字节来记录 万国码,为何这么设计呢?平常使用获得的字符对应的字符编码没有必要占用这么多字节,例如 0000 00000000 0000 0000 0000 都能表示 0,那使用更短的字节所占用的空间更小,传输的速度更快。数组

小插曲

在统一编码的过程当中还出现了一个字符集 UCS-2,它固定使用 2个字节来编码 与 UTF 可变长度字符编码有必定程度上的不一样,可是随着统一进程下被 UTF-16 收编了。

JavaScript 字符处理

了解字符基本原理和进程后,那么 JavaScript 是什么编码呢?没错它就刚才 小插曲 中提到的 UCS-2,缘由是 JavaScript 诞生时 UTF-16 尚未出现。

可是如今你们都在使用 UTF 可变长度字符编码UTF-16 的可变字节为 2个或者 4个,而 UCS-2 却只有 2个。这样两个字符集之间就有存在一个 UCS-2 没法识别的 4字节字符,JavaScript 在处理字符时会傻傻的按着 UCS-2 的两字节去处理,再加上字典里没有这个字符笨笨的小脑壳瓜没法处理只能输出乱码。

因为 emoji 表情的普及,并且 emoji 恰好就是处于 UCS-2字典以外,在前端开发中遇到可能出现 emoji 的地方须要当心谨慎:

长度

BUG 预警

如今最为经常使用的 emoji 表情为 4个字节编码表示,因为 UCS-2 固定两个字节,在统计长度时 emoji 会被当作两个 UCS-2 字符,结果会和咱们预期的输出大了一倍。

let emoji = "😊";

// 输出 2
console.log(emoji.length);
复制代码
BUG 解除

利用 es6 的 Array.prototype.fromspread 来作字符串转数组并计算长度:

let emoji = "😊";

// 输出 1
console.log(Array.from(emoji).length);

// 输出 1
console.log([...emoji].length);
复制代码

若是不支持 Array.prototype.from 能够利用正则替换把 4字节的字符替换为 _ 并计算长度:

let emoji = "😊";

function countSymbols(string) {
    var regexAstralSymbols = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
    return string
        .replace(regexAstralSymbols, '_')
        .length;
}

// 输出 1
console.log(countSymbols(emoji));
复制代码

对于其余的字符串操做,例如拼接或者替换也能够利用数组来实现。

反转字符串

如同上面所讲 emoji 会被当作两个 UCS-2 字符,反转的时候 4个完整的字节会被硬生生的拆分开来,可使用 Esrever 来解决。

let emoji = "😊";

// 输出为两个乱码字符
console.log(emoji.split('').reverse().join(''));
复制代码

字符编码转换

在使用 String.prototype.charCodeAtString.fromCharCode 会出现问题。可使用 ES6 的两个新方法来替换 String.prototype.codePointAtString.fromCodePoint

正则匹配

正则里 . 表示匹配一个字符,可是 UTF-16 4字节字符会被当作两个字符来处理,进而引发错误。ES6 给出了新的解决方法加上 u 标志 /./u.test('😊'),因此写正则的时候要记得加上哦。

字符串遍历

对于字符串的遍历可使用 for...of 语句。

场景

若是后端数据库运行存储 emoji 做为用户名时,前端在限制用户名长度判断时须要注意UTF-16 4字节字符带来的统计错误,其余相似场景同理可得。

小提示:在作微信公众号开发时,因为用户名和用户输入可能出现 emoji 等字符,须要对数据库进行字符集的设置。

不要问我为何知道,由于个人眼里常含泪水。

一块儿成长

在困惑的城市里总少不了并肩同行的 伙伴 让咱们一块儿成长。

  • 若是您想让更多人看到文章能够点个 点赞
  • 若是您想激励小二能够到 Github 给个 小星星
  • 若是您想与小二更多交流添加微信 m353839115

微信公众号

本文原稿来自 PushMeTop

相关文章
相关标签/搜索