Unicode是什么
目前,Unicode的最新版本是7.0版,一共收入了109449个符号,其中的中日韩文字为74500个。可以近似认为,全世界现有的符号当中,三分之二以上来自东亚文字。比如,中文"好"的码点是十六进制的597D。
// 查询一个中文的
"好".charCodeAt(0).toString(16); // output: '597d'
String.fromCodePoint('0x597d'); // output: '好'
'\u597d' // output: '好'
"好".charCodeAt(0); // output: 22909
"好".codePointAt(0); // output: 22909
String.fromCodePoint(22909); // output: '好'
String.fromCharCode("22909"); // output: '好'
Unicode不是一次性定义的,而是分区定义。每个区可以存放65536个(216)字符,称为一个平面(plane)。目前,一共有17个(25)平面,也就是说,整个Unicode字符集的大小现在是221。
最前面的65536个字符位,称为基本平面(缩写BMP),它的码点范围是从0一直到216-1,写成16进制就是从U+0000到U+FFFF。所有最常见的字符都放在这个平面,这是Unicode最先定义和公布的一个平面。
剩下的字符都放在辅助平面(缩写SMP),码点范围从U+010000一直到U+10FFFF。
Unicode只规定了每个字符的码点,到底用什么样的字节序表示这个码点,就涉及到编码方法。
UTF-32与UTF-8
UTF-32
优点:
- 转换规则简单直观
- 查找效率高
缺点:
- 浪费空间,同样内容的英语文本,它会比ASCII编码大四倍
结果: 没有人使用这种编码方法,HTML 5标准明文规定,网页不得编码成UTF-32。
UTF-8
是一种变长的编码方法,字符长度从1个字节到4个字节不等。越是常用的字符,字节越短,最前面的128个字符,只使用1个字节表示,与ASCII码完全相同。 编号范围 字节 0x0000 - 0x007F 1 0x0080 - 0x07FF 2 0x0800 - 0xFFFF 3 0x010000 - 0x10FFFF 4
Example Func
function hexBuf(buffer) {
return [...new Uint8Array(buffer)]
.map(x => x.toString(16).padStart(2, '0'))
.join(' ');
}
function strToUint8Arr(text) {
let byteArray = new Uint8Array(text.length);
for (let i = 0; i < text.length; i++) {
byteArray[i] = text.charCodeAt(i)
}
return byteArray;
}
function utf8_ByteLength(string) {
var len = 0,
c = 0;
for (var i = 0; i < string.length; ++i) {
c = string.charCodeAt(i);
if (c < 128)
len += 1;
else if (c < 2048)
len += 2;
else if ((c & 0xFC00) === 0xD800 && (string.charCodeAt(i + 1) & 0xFC00) === 0xDC00) {
++i;
len += 4;
} else
len += 3;
}
return len;
}
function utf8_read(buffer, start, end) {
var len = end - start;
if (len < 1)
return "";
var parts = null,
chunk = [],
i = 0, // char offset
t; // temporary
while (start < end) {
t = buffer[start++];
if (t < 128)
chunk[i++] = t;
else if (t > 191 && t < 224)
chunk[i++] = (t & 31) << 6 | buffer[start++] & 63;
else if (t > 239 && t < 365) {
t = ((t & 7) << 18 | (buffer[start++] & 63) << 12 | (buffer[start++] & 63) << 6 | buffer[start++] & 63) - 0x10000;
chunk[i++] = 0xD800 + (t >> 10);
chunk[i++] = 0xDC00 + (t & 1023);
} else
chunk[i++] = (t & 15) << 12 | (buffer[start++] & 63) << 6 | buffer[start++] & 63;
if (i > 8191) {
(parts || (parts = [])).push(String.fromCharCode.apply(String, chunk));
i = 0;
}
}
if (parts) {
if (i)
parts.push(String.fromCharCode.apply(String, chunk.slice(0, i)));
return parts.join("");
}
return String.fromCharCode.apply(String, chunk.slice(0, i));
}
function utf8_write(string, buffer, offset) {
var start = offset,
c1, // character 1
c2; // character 2
for (var i = 0; i < string.length; ++i) {
c1 = string.charCodeAt(i);
if (c1 < 128) {
buffer[offset++] = c1;
} else if (c1 < 2048) {
buffer[offset++] = c1 >> 6 | 192;
buffer[offset++] = c1 & 63 | 128;
} else if ((c1 & 0xFC00) === 0xD800 && ((c2 = string.charCodeAt(i + 1)) & 0xFC00) === 0xDC00) {
c1 = 0x10000 + ((c1 & 0x03FF) << 10) + (c2 & 0x03FF);
++i;
buffer[offset++] = c1 >> 18 | 240;
buffer[offset++] = c1 >> 12 & 63 | 128;
buffer[offset++] = c1 >> 6 & 63 | 128;
buffer[offset++] = c1 & 63 | 128;
} else {
buffer[offset++] = c1 >> 12 | 224;
buffer[offset++] = c1 >> 6 & 63 | 128;
buffer[offset++] = c1 & 63 | 128;
}
}
return offset - start;
}
function utf16ToStr(data) {
var str = '',
i;
for (i = 0; i < data.length; i++) {
var value = data[i];
if (value < 0x80) {
str += String.fromCharCode(value);
} else if (value > 0xBF && value < 0xE0) {
str += String.fromCharCode((value & 0x1F) << 6 | data[i + 1] & 0x3F);
i += 1;
} else if (value > 0xDF && value < 0xF0) {
str += String.fromCharCode((value & 0x0F) << 12 | (data[i + 1] & 0x3F) << 6 | data[i + 2] & 0x3F);
i += 2;
} else {
// surrogate pair
var charCode = ((value & 0x07) << 18 | (data[i + 1] & 0x3F) << 12 | (data[i + 2] & 0x3F) << 6 | data[i + 3] & 0x3F) - 0x010000;
str += String.fromCharCode(charCode >> 10 | 0xD800, charCode & 0x03FF | 0xDC00);
i += 3;
}
}
return str;
}