Javascript:unicode 字符到基于 BYTE 的十六进制转义序列(不是代理项)

Javascript: unicode character to BYTE based hex escape sequence (NOT surrogates)

在 javascript 中,我正在尝试将 unicode 转换为与 C:

兼容的基于字节的十六进制转义序列

即。 </code></p> <p>变为:<code>\xF0\x9F\x98\x84(正确)

不是 javascript 代理人,不是 \uD83D\uDE04(错误)

我无法弄清楚 C 想要的四个字节与 javascript 使用的两个代理项之间的数学关系。我怀疑该算法比我微弱的尝试复杂得多。

感谢任何提示。

您的 C 代码需要一个 UTF-8 string (the symbol is represented as 4 bytes). The JS representation you see is UTF-16 但是(该符号表示为 2 uint16s,一个代理对)。
您首先需要获取符号的 (Unicode) 代码点(来自 UTF-16 JS 字符串),然后从中构建它的 UTF-8 表示。

从 ES6 开始,您可以在第一部分使用 codePointAt method,即使不支持,我也建议将其用作 shim。我猜你不想自己解码代理对:-)
至于其他的,我认为没有库方法,但是你可以自己写 according 到规范:

function hex(x) {
    x = x.toString(16);
    return (x.length > 2 ? "\u0000" : "\x00").slice(0,-x.length)+x.toUpperCase();
}
var c = "";
console.log(c.length, hex(c.charCodeAt(0))+hex(c.charCodeAt(1))); // 2, "\uD83D\uDE04"
var cp = c.codePointAt(0);
var bytes = new Uint8Array(4);
bytes[3] = 0x80 | cp & 0x3F;
bytes[2] = 0x80 | (cp >>>= 6) & 0x3F;
bytes[1] = 0x80 | (cp >>>= 6) & 0x3F;
bytes[0] = 0xF0 | (cp >>>= 6) & 0x3F;
console.log(Array.prototype.map.call(bytes, hex).join("")) // "\xf0\x9f\x98\x84"

(在Chrome测试)

在这里找到了解决方案:http://jonisalonen.com/2012/from-utf-16-to-utf-8-in-javascript/

我永远也想不通那个数学,哇。

稍微缩小了

function UTF8seq(s) {
        var i,c,u=[];
        for (i=0; i < s.length; i++) {
            c = s.charCodeAt(i);
                if (c < 0x80) { u.push(c); }
                else if (c < 0x800) { u.push(0xc0 | (c >> 6), 0x80 | (c & 0x3f)); }
                else if (c < 0xd800 || c >= 0xe000) { u.push(0xe0 | (c >> 12),  0x80 | ((c>>6) & 0x3f), 0x80 | (c & 0x3f));  }
                else {  i++;  c = 0x10000 + (((c & 0x3ff)<<10) | (s.charCodeAt(i) & 0x3ff));
                        u.push(0xf0 | (c >>18),  0x80 | ((c>>12) & 0x3f),  0x80 | ((c>>6) & 0x3f), 0x80 | (c & 0x3f)); }        
        }
        for (i=0; i < u.length; i++) { u[i]=u[i].toString(16); }
        return '\x'+u.join('\x');
}

encodeURIComponent 是否有效:

var input = "\uD83D\uDE04";
var result = encodeURIComponent(input).replace(/%/g, "\x"); // \xF0\x9F\x98\x84

Upd: 其实C字符串可以包含数字和字母不用转义,但是如果真的需要转义的话:

function escape(s, escapeEverything) {
    if (escapeEverything) {
        s = s.replace(/[\x10-\x7f]/g, function (s) {
            return "-x" + s.charCodeAt(0).toString(16).toUpperCase();
        });
    }
    s = encodeURIComponent(s).replace(/%/g, "\x");
    if (escapeEverything) {
        s = s.replace(/\-/g, "\");
    }
    return s;
}