Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

javaScript中的Unicode #6

Open
ixlei opened this issue May 20, 2018 · 0 comments
Open

javaScript中的Unicode #6

ixlei opened this issue May 20, 2018 · 0 comments

Comments

@ixlei
Copy link
Owner

ixlei commented May 20, 2018

javaScript中的Unicode

踩坑 在做某个业务的时候,后端童鞋给到的某个字段的值大概都长这样 javascript "\n#\u0008\u0005\u0012\u001f\u0012\u001d\u0005星球大战\u0006:原力觉醒\n\u000f\u0008\u0006\u0012\u000b\u0012\t张学友\n\n\u0008\u0003\u0012\u0006\u0012\u0004Dior\n\u0012\u0008\u0007\u0012\u000e\u0012\u000c英雄联盟" 对于这样的数据,我是拒绝的。对于这些 unicode,怎么解析呢?它到底是什么?

什么是编码

其实编码原理很简单,在计算中并非直接存储字符(英文、中文等),而是存储这些字符对应的一个数字,这些字符在网络传输的时候,也是传输字符对应的数字,编码就是将字符转化成相应的数字。

ASCII

大学C语言入门课程最先学习的知识,它用了一个字节的7位表示一个字符,比如字符A的ASCII码是65。ASCII码只用了7个bit编码,注定能编码的字符很少,只有128个。

Unicode编码

ASCII编码只能编码128个字符,而中国汉子就有6000 +,这样显然不够的,然后中国推出GBK 编码,用了两个字节来编码。中国编码用了GBK,那其他国家呢?于是为了统一,推出了Unicode编码。在1991年推出了UCS统一编码,实际应用的是USC-2,用了2个字节来编码,能编码65536个字符。�JavsScript中的编码就是用的这个编码方式。

编码都是不涉及计算机存储,传输的。但是在遇到两个字节编码的字符的时候,有个系统是大端顺序读取,Windows就是这样,而Mac上是按照小端顺序读取。如果没有个转化格式,那么就乱了,此时UTF(Unicode Transformation Format,简称为UTF)就产生了。因此,UTF-16使用了**大端序(Big-Endian,简写为UTF-16 BE)、小端序(Little-Endian,简写为UTF-16 LE)以及BOM(byte order mark)**的概念。避免上述情况的出现。

JavaScript中的编码

JavaScript刚创建出来的时候,只有USC-2编码方式可选,所以就一只用了这个编码方式。上文也提到USC-2一开始使用了两个字节来编码,能够编码65536个字符,从0x0 - 0xFFFF,这个也被称为基本平面(BMP-—Basic Multilingual Plane)。但是后来发现这样的Unicode编码也是不够用,扩展了其他补充平面,从0x010000 - 0x10FFFF,共16个。对于补充平面的字符。对于UTF-16编码方式来说,在0x0 - 0xFFFF之间的编码方式直接使用了2个字节,而补充平面使用了4个字节来编码,其中前两个字节范围是0xD800 - 0xDBFF,后两个字节范围是0xDC00 - 0xDFFF。通过下面的方式完成映射:

H = Math.floor((c-0x10000) / 0x400)+0xD800 
L = (c  0x10000) % 0x400 + 0xDC00

USC-2编码的那些坑

var text = "𠮷"
console.log(text.length) // 2
console.log(/^.$/.test(text)) // false
console.log(text.split('').reverse()) // ["�", "�"]
console.log(String.fromCharCode(text.codePointAt(0))) // "��"

(1)判断长度失效

对于ES5来说,可以将此类转化以下

var regexAstralSymbols = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g; // 匹配UTF-16的代理对
 
function countSymbols(string) {
	return string
		.replace(regexAstralSymbols, '_')
		.length;
}
countSymbols("𠮷"); // 1

对于ES6来说

function codePointLength(text) {
    var result = text.match(/[\s\S]/gu);
    return result ? result.length : 0;
}
codePointLength("𠮷") // 1

(2)正则表达式

console.log(/^.$/u.test(text)); // true

字符反转

function reverse(string) {
	return Array.from(string).reverse().join('');
}
reverse("𠮷") // "𠮷"

String.fromCharCode

var text = "𠮷";
console.log(text.codePointAt(0)) // 0x20bb7 (unicode)
var hightByte = text.charCodeAt(0) // 0xd842
var lowByte = text.charCode(1) // 0xdfb7
console.log(String.fromCharCode(hightByte, lowByte)) // "𠮷"
console.log(String.fromCodePoint(text.codePointAt(0))) // "𠮷"

写在最后

最后发现这样的编码无法编码成想要的字符,最后让后端童鞋编码成base64编码,然后解码。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant