string与unicode码点之间的转换

目录
文章目录隐藏
  1. 那么如何将一个字符串转为一个 unicode 码点。
  2. 那么如何将一个 unicode 码点转为一个字符串?
  3. String.fromCodePoint(num1, num2….)
  4. String.prototype.charAt(index)
  5. 比较:

在 JavaScript 中,字符串使用了 UTF-16 编码,该编码使用一个 16 比特的编码单元来表示大部分常见的字符,使用两个代码单元表示不常用的字符。

在 JavaScript 中 unicode 是以十六进制代码外加转义字符 “\u” 来表示的字符串。

"\uxxxx"

使用 “\u” 来对一个 Unicode 来进行解码,获得字符串。

那么如何将一个字符串转为一个 unicode 码点。

String.prototype.charCodeAt(index)

charCodeAt 字符串的实例方法,返回 0 ~ 65535 之间的整数,表示给定索引处的 UTF-16 代码单元。如果 index,不是一个数值,就默认是 0,如果超出范围,返回 NaN。

index
index 转为数值,如果 Number 转换中不是一个数字,默认 index 是 0.
如果 index 不在 0~str.length 范围,返回 NaN。

注意,charCodeAt 只能表示基础平面那的 unicode 码点,对于辅助平面内的码点是不能表示的。

所以我们为了表示出辅助平面的码点,我们需要借助代理对,使用高位+地位来构成一个真正的字符。但是,这会造成一个问题,就是我们获取的码点也是代理过去的码点,即 0xD800~0xDB000xDC00~0xDFFF 两个之间的码点。

那么我们怎么才能修复一下 charCodeAt,来让它支持出现 在辅助平面的码点并返回。

// 下面的代码是出现了未知的非基础平面的范围。
 
function fixedCharCodeAt (str, idx) {
    idx = idx || 0;  // 默认不存在会是 0。
    var code = str.charCodeAt(idx); // 先获取 基础平面内的码点。
    var hi, low;  // 高位 and 地位。
    if (0xD800 <= code && code <= 0xDBFF){ // 高位区间
        hi = code;  
        low = str.charCodeAt(idx + 1);  // 代理对的第二个 低位。
        if (isNaN(low)) {  // index 超出长度会返回 NaN
            throw 'High surrogate not followed by low surrogate in fixedCharCodeAt()';
        }
        return ((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000;
    }
    if (0xDC00 <= code && code <= 0xDFFF) {
        hi = str.charCodeAt(idx-1);
        low = code;
        return ((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000;
    }
    return code;  // 超出了范围返回 NaN,以及就是返回基础平面的码点。
}

fixedCharCodeAt ('\uD800\uDC00', 0); // 65536  基础平面是 0~65535 之间
fixedCharCodeAt ('\uD800\uDC00', 1); // 65536

对于上面的 ((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000,我们其实是利用了一个反推,在 Unicode 3.0 给出了辅助平面去求得基本平面映射的公式。Unicode 3.0 公式,我们可以从基础平面公式 ((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000 反推回去得到一个辅助平面的 unicode 码点。

那么如何将一个 unicode 码点转为一个字符串?

String.fromCharCode(num1,num2....)

fromCharCode 字符串静态方法,用于将 unicode 码点转为对应的字符串。

参数范围在 0 ~ 65535 之间,大于的不做检查,比如 0x12345 —> 0x2345,返回一个字符串。

String.fromCharCode(65, 66, 67);   // 返回 "ABC"
String.fromCharCode(0x2014);       // 返回 "—"
String.fromCharCode(0x12014);      // 也是返回 "—"; 数字 1 被剔除并忽略
String.fromCharCode(8212);         // 也是返回 "—"; 8212 是 0x2014 的十进制表示
String.fromCharCode(0xD83C, 0xDF03); // Code Point U+1F303 "Night with
String.fromCharCode(55356, 57091);   // Stars" == "\uD83C\uDF03"
 
String.fromCharCode(0xD834, 0xDF06, 0x61, 0xD834, 0xDF07); // "\uD834\uDF06a\uD834\uDF07"

String.fromCodePoint(num1, num2….)

fromCodePoint 字符串静态方法,用于将 unicode 码点转为对应的字符串。如果传入无效的 Unicode 编码,将会抛出一个 RangeError 的异常。

String.fromCodePoint(42);       // "*"
String.fromCodePoint(65, 90);   // "AZ"
String.fromCodePoint(0x404);    // "\u0404"
String.fromCodePoint(0x2F804);  // "\uD87E\uDC04"
String.fromCodePoint(194564);   // "\uD87E\uDC04"
String.fromCodePoint(0x1D306, 0x61, 0x1D307) // "\uD834\uDF06a\uD834\uDF07"
 
String.fromCodePoint('_');      // RangeError
String.fromCodePoint(Infinity); // RangeError
String.fromCodePoint(-1);       // RangeError
String.fromCodePoint(3.14);     // RangeError
String.fromCodePoint(3e-2);     // RangeError
String.fromCodePoint(NaN);      // RangeError

它和 String.fromCharCode 的区别就是 它可以识别辅助平面的码点,并返回指定的字符。

String.fromCodePoint(0x2F804)
// Polyfill: 它是 ECMASscript 2015 新增的特性。
if (!String.fromCodePoint) (function(stringFromCharCode) {
    var fromCodePoint = function(_) {
        var codeUnits = [], codeLen = 0, result = "";
        for (var index=0, len = arguments.length; index !== len; ++index) {
            var codePoint = +argument[index]; // +会进行隐式强制转换,Number()转为一个数
            // `NaN`, `-Infinity`, `+Infinity`
            // 表示码点不会大于 辅助平面最大 0x10FFFF 并且 codePoint>>>0 小数和负数将会变为        
            // 另一个数,所以不会等于本身。
            if (!(codePoint < 0x10FFFF && (codePoint>>>0) === codePoint)) {
                throw RangeError("Invalid code point: " + codePoint);
            }
            if (codePoint <= 0xFFFF) { // BMP codeLen = codeUnits.push(codePoint); // 基础平面的码点 } else { codePoint -= 0x10000; codeLen = codeUnits.push( (codePoint >> 10) + 0xD800,  // 高位
                    (codePoint % 0x400) + 0xDC00 // 低位
                );
            }
            if (codeLen >= 0x3fff) {  // 参数超过 0x3fff,就不需要在寸了。
              result += stringFromCharCode.apply(null, codeUnits);
              codeUnits.length = 0;
            }
        }
        return result + stringFromCharCode.apply(null, codeUnits);
    }
    try {
      // IE 8 支持下面这种添加静态属性。
      Object.defineProperty(String, "fromCodePoint", {
        "value": fromCodePoint, "configurable": true, "writable": true
      });
    } catch(e) {
      // 如果上面不成功,我们将直接赋值即可。
      String.fromCodePoint = fromCodePoint;
    }
})(String.fromCharCode);

关于有符号位移 >> 和 无符号位移 >>>,可以查看 位移

String.prototype.charAt(index)

charAt 方法可以将一个字符串返回指定的字符。 index 的范围是 0~length-1之间,如果不提供,默认使用 0。如果指定的 index 值超出了该范围,则返回一个空字符串。

var anyString = "Brave new world";
 
console.log("The character at index 0   is '" + anyString.charAt(0)   + "'");
console.log("The character at index 1   is '" + anyString.charAt(1)   + "'");
console.log("The character at index 2   is '" + anyString.charAt(2)   + "'");
console.log("The character at index 3   is '" + anyString.charAt(3)   + "'");
console.log("The character at index 4   is '" + anyString.charAt(4)   + "'");
console.log("The character at index 999 is '" + anyString.charAt(999) + "'");

我们在获取字符的长度时,会把辅助平面的看作是两个长度。

function getChar(str, i) {
    var code = str.charCodeAt(i);  // 先获取码点。
    if (isNaN(code)) {
        return ''; // 不在范围内,返回空字符.
    }
    if (code < 0xD800 || code > 0xDFFF) { // 本来就是基础平面的码点。
        return str.charAt(i);  // 直接返回字符
    }
    if (0xD800 <= code && code <= 0xDBFF) {. // 高位在范围内
        if (str.length <= (i+1)) { // 是否还存在低位 throw 'High surrogate without following low surrogate'; } var next = str.charCodeAt(i + 1); if (0xDC00 > next || next > 0xDFFF) { // 低位不在范围内
            throw 'High surrogate without following low surrogate';
        }
        return str.charAt(i) + str.charAt(i + 1); // 返回高位 + 低位
    }
    if (i === 0) {   // 第一位就是低位
        throw 'Low surrogate without preceding high surrogate';
    }
    var prev = str.charCodeAt(i - 1); // 高位
    if (0xD800 > prev || prev > 0xDBFF) {. // 高位不在范围
        throw 'Low surrogate without preceding high surrogate';
    }
    return false;  // 高位存在,低位也存在,低位的字符就不需要在返回出来,统一在高位返回。
}

比较:

charAt charCodeAt
参数 Number 转换,转换后不是一个数值,就使用默认值 0,获取第一个字符。 参数 Number 转换,转换后不是一个数值,就使用默认值 0,获取第一个字符。
返回值是一个字符,只要参数不是 0 ~length – 1,包括 Infinity 返回空字符。 返回值是一个字符,只要参数不是 0 ~length – 1,包括 Infinity 返回 NaN。
fromCharCode fromCodePoint
参数 Number 转换,转换后不是一个数值,就会返回 “\x00″。 参数 Number 转换,转换后不是一个数值,就会抛出异常 RangeError。

「点点赞赏,手留余香」

0

给作者打赏,鼓励TA抓紧创作!

微信微信 支付宝支付宝

还没有人赞赏,快来当第一个赞赏的人吧!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
码云笔记 » string与unicode码点之间的转换

发表回复