javascript处理汉字到unicode的转换
2020-12-13 16:09
标签:ring lob first tin 方式 res 字符 argument any 最近项目中发现个问题,就是javascript的String.fromCharCode对超过两个字节的unicode不能很好的返回对应的字。 测试如下: 也就是说 只要超出了两个字节的unicode,js都没有很好的解析。 事实上,不仅仅是fromCharCode,javascript里面大部分字符处理函数都无法很好的处理超过两个字节的字符的问题。 我们一直都认为汉字是双字节的,实际上根据unicode5.0规范。汉字的范围如下: 可以看到 其中 CJK统一汉字扩充B的范围就不是双字节的。上面提到的”??”就在这个范围里。当然大部分的汉字都是双字节的。 CJK统一汉字扩充B的汉字我们可以在这看到个大概: 更加完整的unicode范围,可以参考这个文章,虽然年代有些久远。 javascript之所以会有这样的问题,是因为javascript使用了一种叫做UCS-2的编码方式。UCS-2编码只能处理两个字节的字符。而对于 对于上面的 更加具体的javascript的编码历史,可以参考阮一峰的文章。 在es6的规范里,已经针对这种双字节的问题做了处理,提供了几个方法: 于是我们可以这样: 不过很显然支持性很一般。 fromCodePoint的实现: codePointAt的实现: 有了上面的兼容处理,我们就可以很好的处理unicode与多字节字符之间的转换了。 作为10天设计出来的语言,javascript总是有这样那样的坑,实在是让人很无奈。总是要让人花一大堆时间擦屁股。 原文:大专栏 javascript处理汉字到unicode的转换 javascript处理汉字到unicode的转换 标签:ring lob first tin 方式 res 字符 argument any 原文地址:https://www.cnblogs.com/wangziqiang123/p/11618243.html
1
2
3
String.fromCharCode('0x54c8') //正常返回"哈"
String.fromCharCode('0x20087') //应该返回"??",但是此处返回了""
汉字的unicode区间
Block名称
开始码位
结束码位
字符数
CJK统一汉字
4E00
9FBB
20924
CJK统一汉字扩充A
3400
4DB5
6582
CJK统一汉字扩充B
20000
2A6D6
42711
CJK兼容汉字
F900
FA2D
302
CJK兼容汉字
FA30
FA6A
59
CJK兼容汉字
FA70
FAD9
106
CJK兼容汉字补充
2F800
2FA1D
542
http://www.chinesecj.com/code/ext-b.phpjavascript的编码
0x20087
这种不止两个字节的,他会拆成两个双子节的字符。0x20087
它会拆成两个双字节 0xd840
,0xdc87
。然后分别解析发现都是””,就造成了上面的现象。具体的转换公式为:
1
2
3
H = Math.floor((c-0x10000) / 0x400)+0xD800
L = (c - 0x10000) % 0x400 + 0xDC00
es6的解决方案
1
2
String.fromCodePoint():从Unicode码点返回对应字符
String.prototype.codePointAt():从字符返回对应的码点
1
2
3
String.fromCodePoint('0x20087')
('??'.codePointAt(0)).toString(16) //返回20087
mdn有相关的兼容处理,具体方法就是
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
49
50
51
52
53
54
55
56
57
58
59
60
61
if (!String.fromCodePoint) {
(function() {
var defineProperty = (function() {
// IE 8 only supports `Object.defineProperty` on DOM elements
try {
var object = {};
var $defineProperty = Object.defineProperty;
var result = $defineProperty(object, object, object) && $defineProperty;
} catch(error) {}
return result;
}());
var stringFromCharCode = String.fromCharCode;
var floor = Math.floor;
var fromCodePoint = function() {
var MAX_SIZE = 0x4000;
var codeUnits = [];
var highSurrogate;
var lowSurrogate;
var index = -1;
var length = arguments.length;
if (!length) {
return '';
}
var result = '';
while (++index var codePoint = Number(arguments[index]);
if (
!isFinite(codePoint) || // `NaN`, `+Infinity`, or `-Infinity`
codePoint 0 || // not a valid Unicode code point
codePoint > 0x10FFFF || // not a valid Unicode code point
floor(codePoint) != codePoint // not an integer
) {
throw RangeError('Invalid code point: ' + codePoint);
}
if (codePoint 0xFFFF) { // BMP code point
codeUnits.push(codePoint);
} else { // Astral code point; split in surrogate halves
// http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
codePoint -= 0x10000;
highSurrogate = (codePoint >> 10) + 0xD800;
lowSurrogate = (codePoint % 0x400) + 0xDC00;
codeUnits.push(highSurrogate, lowSurrogate);
}
if (index + 1 == length || codeUnits.length > MAX_SIZE) {
result += stringFromCharCode.apply(null, codeUnits);
codeUnits.length = 0;
}
}
return result;
};
if (defineProperty) {
defineProperty(String, 'fromCodePoint', {
'value': fromCodePoint,
'configurable': true,
'writable': true
});
} else {
String.fromCodePoint = fromCodePoint;
}
}());
}
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
if (!String.prototype.codePointAt) {
(function() {
'use strict'; // needed to support `apply`/`call` with `undefined`/`null`
var codePointAt = function(position) {
if (this == null) {
throw TypeError();
}
var string = String(this);
var size = string.length;
// `ToInteger`
var index = position ? Number(position) : 0;
if (index != index) { // better `isNaN`
index = 0;
}
// Account for out-of-bounds indices:
if (index 0 || index >= size) {
return undefined;
}
// Get the first code unit
var first = string.charCodeAt(index);
var second;
if ( // check if it’s the start of a surrogate pair
first >= 0xD800 && first 0xDBFF && // high surrogate
size > index + 1 // there is a next code unit
) {
second = string.charCodeAt(index + 1);
if (second >= 0xDC00 && second 0xDFFF) { // low surrogate
// http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
return (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000;
}
}
return first;
};
if (Object.defineProperty) {
Object.defineProperty(String.prototype, 'codePointAt', {
'value': codePointAt,
'configurable': true,
'writable': true
});
} else {
String.prototype.codePointAt = codePointAt;
}
}());
}
结语
下一篇:PHP 图片水印法