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

时间:2011-08-08 17:11:35

标签: javascript node.js unicode v8 astral-plane

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

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

<script>document.write( "helo" )
document.write( " ⿸子" );
</script>

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

我也被告知,出于任何不可理解的原因,谷歌决定使用16位宽的数据类型来实现字符。虽然我觉得愚蠢,但surrogate codepoints的设计恰恰是为了通过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 )

但这只给了我

���
���
������
������

这背后的想法是,因为处理unicode的javascript规范的脑死亡部分似乎要求授权? /不是彻头彻尾的禁止? /允许?使用代理对,那么也许我的源文件编码(utf-8)可能是问题的一部分。毕竟,在utf-8中有两种编码32位码点的方法:一种是写出第一个代理所需的utf-8个八位字节,然后是第二个代码点。另一种方式(根据utf-8规范,这是首选方式)是计算得到的代码点并写出该代码点所需的八位字节。所以在这里我完全排除源文件编码的问题,只处理数字。上面的代码与Chrome中的document.write()一起使用,提供,所以我知道我的数字是正确的。

叹息。

编辑我做了一些实验,发现当我做的时候

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

我确实在谷歌浏览器窗口和控制台上获得了正确的结果:


2
0xd864
0xdd0e

2
0xd864
0xdd0e

然而,这是我在使用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>

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

注意我已将此问题交叉发布到v8-users mailing list

2 个答案:

答案 0 :(得分:10)

最近的演示文稿涵盖了流行语言中Unicode的各种问题,并且不适合Javascript:The Good, the Bad, & the (mostly) Ugly

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

  

UTF-16néeUCS-2诅咒

     

像其他几种语言一样,Javascript   患有UTF-16诅咒。除了Javascript有一个偶数   更糟糕的形式,UCS-2诅咒。像charCodeAt和   fromCharCode只处理16位数量,而不是真实的,   21位Unicode代码点。因此,如果要打印出来   比如,U + 1D49C,MATHEMATICAL SCRIPT CAPITAL A,你必须这样做   指定不是一个字符而是两个“char单元”:“\ uD835 \ uDC9C”。

// ERROR!! 
document.write(String.fromCharCode(0x1D49C));
// needed bogosity
document.write(String.fromCharCode(0xD835,0xDC9C));

答案 1 :(得分:2)

我认为这是一个console.log问题。由于console.log仅用于调试,因此从节点通过http输出到浏览器时会出现同样的问题吗?