代码改变世界

了解Unicode编码

2019-12-04 22:22  龙恩0707  阅读(...)  评论(...编辑  收藏

一. Unicode是什么?

Unicode是一种字符编码方案,它为每种语言中的每个字符都设定了统一唯一的二进制编码。以实现跨语言、跨平台进行文本转换。

Unicode是为了解决传统字符编码方案的局限而产生的。

Unicode编码的发展及详细介绍可以看这篇文章(https://www.php.cn/js-tutorial-414753.html)。

Unicode字符编码是用一个码位映射一个字符,码位值的范围是从 U+0000 到 U+10FFFF。

码位:一般是被格式化为十六进制数字的,零填充至少四位数,格式为 U + 前缀。

比如 A的码位:U+0041, a的码位:U+0061;

因为A的ASCII十进制为 65; a的ASCII的十进制为97; 我们可以在chrome浏览器下测试下即可:

'A'.charCodeAt(); // 打印65

因此 字符 A 十进制为65,转换成十六进制就是41了,十六进制转十进制的方法为 65 = 4 * 16 + 1; 因此变成Unicode码位的话: U+0041了。

Unicode最前面的65536个字符位,称为零号平面,它的码位范围是从 U+0000 到 U+FFFF; 我们最常见的字符都在这里面了。

Unicode转义

1. 16进制转义

"A" 转义为:'\x41'; "a" 转义为: '\x61';

2. Unicode转义

A的Unicode码位为: 'U+0041'; 因此 字符A的Unicode的转义就变成了 '\u0041'; 我们可以在chrome控制台打印下就知道了。

在ECMAScript6中,引入了一种新的转义序列:Unicode码位转义: 比如:'\u{41}'; 使用大括号对16进制数字,在大括号之间可以使用最多6个十六进制数字。

字符串方法中的Unicode

1. String.fromCharCode()

String.fromCharCode() 方法可以将一个码位转换为字符,但是它只适用于BMP范围内的码位(即从 U+0000 到 U+FFFF)。如果将它用于转换超过BMP外的码位,将不会得到想要的结果。

fromCharCode()可以接受一个指定的Unicode的值,然后返回一个字符串。该方法是String的静态方法,字符串中的每个字符都由单独的Unicode数字编码指定。基本语法如下所示:

String.fromCharCode(n1, n2, ......nx);

比如如下代码:

var n = String.fromCharCode(72,69,76,76,79); 
console.log(n); // 打印的值为:"HELLO"

String.fromCharCode() 的缺点是:

对于在 U+0000 到 U+FFFF 范围之外的码位是获取不到结果的,我们看下:

String.fromCharCode(0x1F4A9);

打印的结果如下:

解决的方法当然也有,但是方法也不是很好,但是幸运的是,ES6中引入了 String.fromCodePoint(codePoint). 该方法的优点是可以用于任何的Unicode编码,它是范围更广,是从 U+0000 到 U+10FFFF; 我们可以继续使用该方法测试下上面的demo;

String.fromCodePoint(0x1F4A9);

在chrome浏览器下执行的结果如下所示:

2. String.prototype.charAt(position)

该方法是用来检索包含字符串中的第一个字符。

比如如下代码:

'abcdeb'.charAt(1); // 打印 b

3. String.prototype.charCodeAt(position)

该方法的含义是:从字符串中获取码位, 检索字符串中第一个字符的码位。

比如如下代码:

'ABC'.charCodeAt(1); // 输出结果为66;

如上是字符串 'ABC'; 找到第2个字符串的码位。

二:JS中Unicode编码与String相互转换

1. 字符串转Unicode

第一种方式:

var str='\u6211\u662f\u4e2d\u56fd\u4ebaChina';
var ret1 = eval("'" + str + "'");
console.log(ret1); // 打印出:我是中国人China

第二种方式:

var str='\u6211\u662f\u4e2d\u56fd\u4ebaChina';
var ret2 = (new Function("return '" + str + "'"))();
console.log(ret2); // 打印出:我是中国人China

第三种方式:

var str='\u6211\u662f\u4e2d\u56fd\u4ebaChina';
var ret3 = unescape(str.replace(/\u/g, '%u'));
console.log(ret3); // 打印出:我是中国人China

2. Unicode转字符串

function string2unicode(str) {
  var html = '';
  for (let i = 0; i < str.length; i++) {
      console.log(str.charCodeAt(i))
    html += "\\u" + str.charCodeAt(i).toString(16);
  }
  return html;
}
var str = "我是中国人";
var s2u = string2unicode(str);
console.log(s2u); // 打印出: \u6211\u662f\u4e2d\u56fd\u4eba
console.log(eval("'"+s2u+"'")); // 输出:我是中国人

如上代码,使用的语法是:number.toString(radix);

radix参数可选;它值可以是2、8、16,表示以多少进制来显示。
更多了解可以看对应的API(https://www.runoob.com/jsref/jsref-tostring-number.html)

如下代码演示:

var num = 15;
var a = num.toString();
var b = num.toString(2);
var c = num.toString(8);
var d = num.toString(16);

console.log(a); // 15
console.log(b); // 1111
console.log(c); // 17
console.log(d); // f

如上字符串转Unicode的方法 string2unicode 有缺陷的,比如中文里面包含英文的话,就不行了,请看如下代码:

function string2unicode(str) {
  var html = '';
  for (let i = 0; i < str.length; i++) {
    html += "\\u" + str.charCodeAt(i).toString(16);
  }
  return html;
}
var str = "我是中国人a"; 
var s2u = string2unicode(str);
console.log(s2u); // 打印结果为: \u6211\u662f\u4e2d\u56fd\u4eba\u61
console.log(eval("'"+s2u+"'"));

如上代码就报错了,因为JS自身的Unicode转字符串不能识别不足4位的unicode。因此我们要对 string2unicode方法改进一下。

function string2unicode(str) {
  var html = '';
  var rets = '';
  for (let i = 0; i < str.length; i++) {
      // 获取码位
    var c1 = str.charCodeAt(i);
    // 转换成16进制
    var c16 = c1.toString(16);
    // 0xf 代表16进制f,转换成10进制就是15
    if (c1 < 0xf) {
      html += "\\u" + "000" + c16;
    } else if (c1 < 0xff) { 
      html += "\\u" + "00" + c16;
    } else if (c1 < 0xfff) {
      html += "\\u" + '0' + c16;
    } else {
      html += "\\u" + c16;
    }
  }
  rets += html;
  return rets;
}

var str = "我是中国人a"; 
var s2u = string2unicode(str);
console.log(s2u); // 打印结果为: \u6211\u662f\u4e2d\u56fd\u4eba\u61
console.log(eval("'"+s2u+"'")); // 打印: 我是中国人a

我们可以在chrome控制台看下打印信息如下: