摘要:编码迟至年月才公布,明确宣布是的超集,即基本平面字符沿用编码,辅助平面字符定义了个字节的表示方法。的字符函数都受到这一点的影响,无法返回正确结果。但是,这种表示法对字节的码点无效。以上就可以表示出汉字范围编码的正则。
问题出现
在项目中遇到问题
“一二三四五?六七八九十”,被识别为10个字。
一、二、...、十 。呃...似乎有点问题。应该是11个字的啊。
问题就出在?,这个字没有被识别。
问题分析
看看代码:
JavaScript允许直接用码点表示Unicode字符,写法是"反斜杠+u+码点"。码点有十六机制数表示。
但是,这种表示法对4字节的码点无效。ES6修正了这个问题,只要将码点放在大括号内,就能正确识别。
根据汉字unicode范围表发现常用的大多数汉字都可用u4E00-u9FA5来表示。而?的unicode码是U+20BB7,没有被包含。所以,我们需要匹配汉字unicode范围表所有的汉字。
但是, 编码类似u20BB7的4字节的码点不能直接被识别。我们需要理解一下js使用的编码。
JavaScript使用哪一种编码?
JavaScript用的是UCS-2!
UCS的开发进度快于Unicode,1990年就公布了第一套编码方法UCS-2,使用2个字节表示已经有码点的字符。(那个时候只有一个平面,就是基本平面,所以2个字节就够用了。)UTF-16编码迟至1996年7月才公布,明确宣布是UCS-2的超集,即基本平面字符沿用UCS-2编码,辅助平面字符定义了4个字节的表示方法。
由于JavaScript只能处理UCS-2编码,造成所有字符在这门语言中都是2个字节,如果是4个字节的字符,会当作两个双字节的字符处理。JavaScript的字符函数都受到这一点的影响,无法返回正确结果。
unicode
这么多符号,Unicode不是一次性定义的,而是分区定义。每个区可以存放65536个(216)字符,称为一个平面(plane)。目前,一共有17个(25)平面,也就是说,整个Unicode字符集的大小现在是221。
最前面的65536个字符位,称为基本平面(缩写BMP),它的码点范围是从0一直到216-1,写成16进制就是从U+0000到U+FFFF。所有最常见的字符都放在这个平面,这是Unicode最先定义和公布的一个平面。
剩下的字符都放在辅助平面(缩写SMP),码点范围从U+010000一直到U+10FFFF。
UTF-16
到底是把这两个字节当作一个字符还是与后面的两个字节一起当作一个字符呢? 这里有一个很巧妙的地方,在基本平面内,从 U+D800 到
U+DFFF 是一个空段,即这些码点不对应任何字符。因此,这个空段可以用来映射辅助平面的字符。 辅助平面的字符位共有 220220
个,因此表示这些字符至少需要 20 个二进制位。UTF-16将这 20 个二进制位分成两半,前 10 位映射在 U+D800 到
U+DBFF,称为高位(H),后 10 位映射在 U+DC00 到
U+DFFF,称为低位(L)。这意味着,一个辅助平面的字符,被拆成两个基本平面的字符表示。 因此,当我们遇到两个字节,发现它的码点在
U+D800 到 U+DBFF 之间,就可以断定,紧跟在后面的两个字节的码点,应该在 U+DC00 到 U+DFFF
之间,这四个字节必须放在一起解读。
总的来说,一个辅助平面的字符,被拆成两个基本平面的字符表示。或者在ES6中可以用"u{20BB7}"来表示。
ES6的支持
ES6可以自动识别4字节的码点。因此,遍历字符串就简单多了。
for (let s of string ) { // ...
}
为了得到字符串的正确长度,可以用下面的方式。
Array.from(string).length [...string].length
码点表示法,JavaScript允许直接用码点表示Unicode字符,写法是"反斜杠+u+码点"。但是,这种表示法对4字节的码点无效。ES6修正了这个问题,只要将码点放在大括号内,就能正确识别。
String.fromCodePoint():从Unicode码点返回对应字符
String.prototype.codePointAt():从字符返回对应的码点
String.prototype.at():返回字符串给定位置的字符
正则表达式,ES6提供了u修饰符,对正则表达式添加4字节码点的支持。
问题解决
所以,我们在正则中表示所有的汉字,需要将不能被直接识别的4字节识别,可以通过ES6的方式,也可以转换成基本平面来表示。我们需要将所有的汉字区间都包含在匹配公式中,从上面的汉字unicode范围表看,自己来手写是很复杂。
还好,有Regenerate可以来完成这件事情。通过它我们可以快速的表示出复杂的正则表达式。
export const character2unicode = regenerate() .addRange(0x4e00, 0x9fa5) .addRange(0x9fa6, 0x9fcb) .addRange(0x3400, 0x4db5) .addRange(0x20000, 0x2a6d6) .addRange(0x2a700, 0x2b734) .addRange(0x2b740, 0x2b81d) .addRange(0x2f00, 0x2fd5) .addRange(0x2e80, 0x2ef3) .addRange(0xf900, 0xfad9) .addRange(0x2f800, 0x2fa1d) .addRange(0xe815, 0xe86f) .addRange(0xe400, 0xe5e8) .addRange(0xe600, 0xe6cf) .addRange(0x31c0, 0x31e3) .addRange(0x2ff0, 0x2ffb) .addRange(0x3105, 0x3120) .addRange(0x31a0, 0x31ba) .toRegExp(); // character2unicode // /[u2E80-u2EF3u2F00-u2FD5u2FF0-u2FFBu3105-u3120u31A0-u31BAu31C0-u31E3u3400-u4DB5u4E00-u9FCBuE400-uE5E8uE600-uE6CFuE815-uE86FuF900-uFAD9]|[uD840-uD868uD86A-uD86C][uDC00-uDFFF]|uD869[uDC00-uDED6uDF00-uDFFF]|uD86D[uDC00-uDF34uDF40-uDFFF]|uD86E[uDC00-uDC1D]|uD87E[uDC00-uDE1D]/
以上就可以表示出汉字unicode范围编码的正则。感觉可以很愉快的开工。
参考
https://mathiasbynens.be/note...
http://www.ruanyifeng.com/blo...
https://github.com/mathiasbyn...
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/93294.html
摘要:如果转进制,则位进制只能表示个汉字,这个太少了。假设我们用个进制的字符,则可以表示,表示个汉字绰绰有余,但这时候需要多个字符。 项目地址:https://github.com/xinglie/pi... 压缩说明 为了便于在网络上的传输,本人想办法写了一个压缩算法,目前这个版本是压缩好的,带自解压功能以下说明压缩思路: 理想状态下是使用Stirng.prototype.localCom...
摘要:遍历汉字,编码转汉字网上找了一堆代码,这个转那个,那个转这个,最后发现原生已经有对应的方法了。比如输出之后的个汉字 js 遍历汉字,Unicode编码转汉字 网上找了一堆代码,这个转那个,那个转这个,最后发现原生js已经有对应的方法了。 MDN 数字转对应进制的字符串: https://developer.mozilla.org... 写了个页面: http://kylebing.c...
摘要:中国大陆几乎所有的中文系统和国际化的软件都支持。与相应的国家标准中的其它汉字,以上合计个汉字。,全称国家标准信息技术中文编码字符集,是中华人民共和国现时最新的内码字集,是信息技术信息交换用汉字编码字符集基本集的扩充的修订版。 实战PHP导出Excel-CSV文件 导出后的效果 先给各位看一下导出的效果,而后再进行代码分析 showImg(https://segmentfault.co...
阅读 3180·2021-11-18 10:02
阅读 3403·2021-10-11 10:58
阅读 3313·2021-09-24 09:47
阅读 1084·2021-09-22 15:21
阅读 3803·2021-09-10 11:10
阅读 3243·2021-09-03 10:28
阅读 1713·2019-08-30 15:45
阅读 2073·2019-08-30 14:22