javascript处理汉字到unicode的转换

文章目录

最近项目中发现个问题,就是javascript的String.fromCharCode对超过两个字节的unicode不能很好的返回对应的字。

测试如下:

1
2
3
String.fromCharCode('0x54c8') //正常返回"哈"

String.fromCharCode('0x20087') //应该返回"??",但是此处返回了""

也就是说 只要超出了两个字节的unicode,js都没有很好的解析。

事实上,不仅仅是fromCharCode,javascript里面大部分字符处理函数都无法很好的处理超过两个字节的字符的问题。

汉字的unicode区间

我们一直都认为汉字是双字节的,实际上根据unicode5.0规范。汉字的范围如下:

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

可以看到 其中 CJK统一汉字扩充B的范围就不是双字节的。上面提到的”??”就在这个范围里。当然大部分的汉字都是双字节的。

CJK统一汉字扩充B的汉字我们可以在这看到个大概:
http://www.chinesecj.com/code/ext-b.php

更加完整的unicode范围,可以参考这个文章,虽然年代有些久远。

javascript的编码

javascript之所以会有这样的问题,是因为javascript使用了一种叫做UCS-2的编码方式。UCS-2编码只能处理两个字节的字符。而对于0x20087这种不止两个字节的,他会拆成两个双子节的字符。

对于上面的0x20087它会拆成两个双字节 0xd840 ,0xdc87。然后分别解析发现都是””,就造成了上面的现象。具体的转换公式为:

1
2
3
H = Math.floor((c-0x10000) / 0x400)+0xD800

L = (c - 0x10000) % 0x400 + 0xDC00

更加具体的javascript的编码历史,可以参考阮一峰的文章

es6的解决方案

在es6的规范里,已经针对这种双字节的问题做了处理,提供了几个方法:

1
2
String.fromCodePoint():从Unicode码点返回对应字符
String.prototype.codePointAt():从字符返回对应的码点

于是我们可以这样:

1
2
3
String.fromCodePoint('0x20087') 

('??'.codePointAt(0)).toString(16) //返回20087

不过很显然支持性很一般。
mdn有相关的兼容处理,具体方法就是

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
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 < length) {
        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;
    }
  }());
}

codePointAt的实现:

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;
    }
  }());
}

有了上面的兼容处理,我们就可以很好的处理unicode与多字节字符之间的转换了。

结语

作为10天设计出来的语言,javascript总是有这样那样的坑,实在是让人很无奈。总是要让人花一大堆时间擦屁股。

原文:大专栏  javascript处理汉字到unicode的转换

原文地址:https://www.cnblogs.com/wangziqiang123/p/11618243.html

时间: 2024-11-05 17:34:10

javascript处理汉字到unicode的转换的相关文章

javaScript 实现Unicode字符转换以及汉字转拼音

一.JavaScript实现汉字转为Unicode 1.通过解编码的方式转换 /* *js Unicode编码转换 */  var decToHex = function(str) {     var res=[];     for(var i=0;i < str.length;i++)         res[i]=("00"+str.charCodeAt(i).toString(16)).slice(-4);     return "\\u"+res.jo

JavaScript中字符串与Unicode编码的互相转换

JavaScript中字符串与Unicode编码的互相转换 这段代码演示了JavaScript中字符串与Unicode编码的转换: // 为了控制台的演示方便, 变量没有添加 var 定义 // 实际编程中请避免 // 字符串 str = "中文"; // 获取字符 char0 = str.charAt(0); // "中" // 数字编码值 code = str.charCodeAt(0); // 20013 // 编码互转 str0 = String.fromC

.Net(c#)汉字和Unicode编码互相转换

{"Tilte": "\u535a\u5ba2\u56ed", "Href": "http://www.cnblogs.com"} 经常遇到这样内容的json字符串,原来是把其中的汉字做了Unicode编码转换. Unicode编码: 将汉字进行UNICODE编码,如:“王”编码后就成了“\王”,UNICODE字符以\u开始,后面有4个数字或者字母,所有字符都是16进制的数字,每两位表示的256以内的一个数字.而一个汉字是由两

python3进行汉字和unicode码的转换

输出某个unicode码对应的汉字和某个汉字对应的unicode编码. # -*- coding=UTF-8 -*- str1 = "\u6000"#某个汉字的unicode码 str2='一'#汉字一 #print(str1.encode('utf-8').decode('unicode_escape'))#python2的写法,python3不能用 print(str1)#输出str1对应的汉字 print(str2.encode('unicode_escape'))#输出汉字一对

JS 汉字与Unicode码的相互转化

js文件中,有些变量的值可能会含有汉字,画面引入js以后,有可能会因为字符集的原因,把里面的汉字都变成乱码.后来发现网上的一些js里会把变量中的汉字都表示成”\u“开头的16进制编码,这样应该可以解决上面的问题. 最近有时间在网上查找了一下实现方式,一种比较大众化的: function tounicode(data) { if(data == '') return '请输入汉字'; var str =''; for(var i=0;i<data.length;i++) { str+="\\

winform学习日志(二十八)----------将汉字转化为拼音,正则表达式和得到汉字的Unicode编码

一:上图,不清楚的看代码注解,很详细了 二:具体代码 窗体代码 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Text.RegularExpressio

【JavaScript】浅析javaScript和HTML与unicode字符集的关系

目录结构: javaScript和HTML支持的字符集 javaScript和HTML如何表现unicode字符集 参考文章 javaScript和HTML支持的字符集 JavaScript是支持unicode的. 现代的浏览器在网页中都支持ASCII字符集.ISO字符集.数学符号.希腊字母.其他符号.HTML5默认使用UTF-8.读者可以点击这儿查看ASCII.unicode和utf-8的关系. javaScript和HTML如何表现unicode字符集 HTML页面使用的是网页文档对象,它是

Js汉字和Unicode编码互转 Unicode加密 Unicode解密

<title>汉字和Unicode编码互转</title> <script Language=Javascript> var classObj= { ToUnicode:function(str) { return escape(str).replace(/%/g,"\\").toLowerCase(); }, UnUnicode:function(str) { return unescape(str.replace(/\\/g, "%&q

Python3的unicode编码转换成中文问题

Python3的unicode编码转换成中文问题 从别的地方搬过来的,担心以后不容易搜索到,就收集过来. 我当时面临的问题是要从C++发json代码出来,用python写了个server,然后返回给C++程序,结果收到的是:httpSvrDataCbUser: {"tranNO": "0808ad498670dc996", "data": "\u65b0A1EY16", "ver": "1.0&q