如何在谷歌v8(和nodejs)中渲染32位unicode字符

flo*_*low 9 javascript unicode v8 node.js astral-plane

有没有人知道如何在谷歌v8中渲染unicode'星界'字符(其CID超出0xffff),javascript vm驱动谷歌chrome和nodejs?

有趣的是,当我给谷歌chrome(它标识为11.0.696.71,在ubuntu 10.4上运行)这样的html页面时:

<script>document.write( "helo" )
document.write( " ??" );
</script>
Run Code Online (Sandbox Code Playgroud)

它将正确地呈现'宽'字符和'窄'字符,但是当我在nodejs(使用console.log())中尝试等效时,我得到一个'宽'字符的单个 (0xfffd,REPLACEMENT CHARACTER).

我也被告知,无论出于何种不可理解的原因,谷歌都决定使用16位宽的数据类型来实现字符.虽然我觉得这很愚蠢,但代理码点的设计恰恰是为了通过16位挑战的路径实现"星际代码点"的"引导".并且不知何故,运行在chrome 11.0.696.71内部的v8似乎使用了这一点unicode-foo或其他魔法来完成它的工作(我好像记得几年前我总是有盒子而不是静态页面).

啊,是的,node --version报道v0.4.10,要弄清楚如何从中获取v8版本号.

更新我在咖啡脚本中做了以下事情:

a = String.fromCharCode( 0xd801 )
b = String.fromCharCode( 0xdc00 )
c = a + b
console.log a
console.log b
console.log c
console.log String.fromCharCode( 0xd835, 0xdc9c )
Run Code Online (Sandbox Code Playgroud)

但这只会给我

???
???
??????
??????
Run Code Online (Sandbox Code Playgroud)

这背后的想法是,因为处理unicode的javascript规范的脑谜部分似乎是强制性的吗?/不是彻头彻尾的禁止?/允许?使用代理对,那么也许我的源文件编码(utf-8)可能是问题的一部分.毕竟,在utf-8中有两种编码32位码点的方法:一种是写出第一个代理所需的utf-8个八位字节,然后是第二个代码点.另一种方式(根据utf-8规范,这是首选方式)是计算得到的代码点并写出该代码点所需的八位字节.所以在这里我完全排除源文件编码的问题,只处理数字.上面的代码确实可以document.write()在chrome中使用, so i know i got the numbers right.

sigh.

EDIT i did some experiments and found out that when i do

var f = function( text ) {
  document.write( '<h1>',  text,                                '</h1>'  );
  document.write( '<div>', text.length,                         '</div>' );
  document.write( '<div>0x', text.charCodeAt(0).toString( 16 ), '</div>' );
  document.write( '<div>0x', text.charCodeAt(1).toString( 16 ), '</div>' );
  console.log( '<h1>',  text,                                 '</h1>'  );
  console.log( '<div>', text.length,                          '</div>' );
  console.log( '<div>0x', text.charCodeAt(0).toString( 16 ),  '</div>' );
  console.log( '<div>0x', text.charCodeAt(1).toString( 16 ),  '</div>' ); };

f( '' );
f( String.fromCharCode( 0xd864, 0xdd0e ) );
Run Code Online (Sandbox Code Playgroud)

i do get correct results in google chrome---both inside the browser window and on the console:


2
0xd864
0xdd0e

2
0xd864
0xdd0e
Run Code Online (Sandbox Code Playgroud)

however, this is what i get when using nodejs' console.log:

<h1> ? </h1>
<div> 1 </div>
<div>0x fffd </div>
<div>0x NaN </div>
<h1> ?????</h1>
<div> 2 </div>
<div>0x d864 </div>
<div>0x dd0e </div>
Run Code Online (Sandbox Code Playgroud)

这似乎表明,解析超出CID的utf-8 0xffff并将这些字符输出到控制台都会被破坏.顺便说一句,python 3.1将字符视为代理对,并可以将字符打印到控制台.

注意我已将此问题交叉发布到v8-users邮件列表.

Ned*_*der 10

最近的演示文稿涵盖了流行语言中Unicode的各种问题,并且对Javascript 不好: 好,坏,和(大多数)丑陋

他用Javascript中的Unicode双字节表示来解决这个问题:

UTF-16néeUCS-2诅咒

像其他几种语言一样,Javascript也遭受了UTF-16诅咒.除了Javascript有更糟糕的形式,UCS-2诅咒.charCodeAt和fromCharCode之类的东西只处理16位数量,而不是真正的21位Unicode代码点.因此,如果要打印出类似U + 1D49C,MATHEMATICAL SCRIPT CAPITAL A的内容,则必须指定不是一个字符而是两个"字符单元":"\ uD835\uDC9C".

// ERROR!! 
document.write(String.fromCharCode(0x1D49C));
// needed bogosity
document.write(String.fromCharCode(0xD835,0xDC9C));
Run Code Online (Sandbox Code Playgroud)