Как отрисовать 32-битные символы Unicode в Google V8 (и Nodejs) - PullRequest
9 голосов
/ 08 августа 2011

У кого-нибудь есть идея, как отобразить символы юникода 'астральная плоскость' (чьи CID превышают 0xffff) в google v8, javascript vm, который управляет как Google Chrome, так и nodejs?

как ни странно, когда я даю Google Chrome (он идентифицируется как 11.0.696.71, работает на Ubuntu 10.4) html-страницу, например:

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

он будет правильно отображать «широкий» символ ? вместе с «узкими», но когда я пробую эквивалент в nodejs (используя console.log()), я получаю один (0xfffd, REPLACEMENT CHARACTER) для «широкого» характер вместо

Мне также сказали, что по непонятной причине Google решил реализовать символы с использованием 16-битного типа данных. в то время как я нахожу это глупым, суррогатные кодовые точки были разработаны именно для того, чтобы обеспечить «каналирование» «астральных кодовых точек» через 16-битные пути. и почему-то v8, работающий внутри chrome 11.0.696.71, по-видимому, использует этот бит unicode-foo или другой магии для своей работы (кажется, я помню, много лет назад у меня всегда были коробки вместо этого даже на статических страницах).

ах да, node --version сообщает v0.4.10, надо выяснить, как получить из этого номер версии v8.

обновление я сделал следующее в coffee-script:

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 )

но это только дает мне

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

Мысль, стоящая за этим, заключается в том, что, поскольку та мозговая часть спецификации javascript, которая имеет дело с юникодом, по-видимому, обязывает? / не прямо запретить? / позволяет? использование суррогатных пар, тогда, возможно, моя кодировка исходного файла (utf-8) может быть частью проблемы. в конце концов, есть два способа кодирования 32-битных кодовых точек в utf-8: один - два, записывают октеты utf-8, необходимые для первого суррогата, затем для второго; Другой способ (который является предпочтительным способом согласно спецификации utf-8) - вычислить результирующую кодовую точку и выписать октеты, необходимые для этой кодовой точки. поэтому здесь я полностью исключаю вопрос кодировки исходного файла, имея дело только с числами. приведенный выше код работает с document.write() в chrome, давая ??, так что я знаю, что я правильно понял числа.

Вздох.

РЕДАКТИРОВАТЬ Я провел несколько экспериментов и обнаружил, что когда я делаю

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

я получаю правильные результаты в Google Chrome --- как в окне браузера, так и на консоли:

?
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>

это, кажется, указывает на то, что как синтаксический анализ utf-8 с CID за 0xffff, так и вывод этих символов в консоль не работает. Кстати, python 3.1 рассматривает персонажа как суррогатную пару и может выводить символ в консоль.

ПРИМЕЧАНИЕ Я пересыл этот вопрос в список рассылки v8 пользователей .

Ответы [ 2 ]

10 голосов
/ 08 августа 2011

Эта недавняя презентация охватывает все виды проблем с Unicode на популярных языках и не относится к Javascript: Хорошее, плохое и (в основном) Уродливое

Онохватывает проблему с двухбайтовым представлением Unicode в Javascript:

UTF-16, UE-2 Curse

Как и некоторые другие языки, Javascript страдает от UTF-16 Curse,За исключением того, что Javascript имеет еще худшую форму, проклятие UCS-2.Такие вещи, как charCodeAt и fromCharCode, имеют дело только с 16-битными значениями, а не с реальными 21-битными кодовыми точками Unicode.Поэтому, если вы хотите распечатать что-то вроде ?, U + 1D49C, МАТЕМАТИЧЕСКИЙ КАПИТАЛ A, вы должны указать не один символ, а две «символьные единицы»: «\ uD835 \ uDC9C».101

// ERROR!! 
document.write(String.fromCharCode(0x1D49C));
// needed bogosity
document.write(String.fromCharCode(0xD835,0xDC9C));
2 голосов
/ 10 августа 2011

Я думаю, что это проблема console.log.Поскольку console.log предназначен только для отладки, возникают ли у вас те же проблемы при выводе данных из узла через http в браузер?

...