Как отрисовать 32-битные символы Unicode в Google V8 (и Nodejs)

У кого-нибудь есть идеи, как визуализировать символы юникода "астральной плоскости" (чьи 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, ЗАМЕНЯЮЩИЙ ХАРАКТЕР) для "широкого" символа.

Мне также сказали, что по какой-то непонятной причине 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() в хроме, даче так что я знаю, что я правильно понял цифры.

вздох.

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

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-users.

2 ответа

Решение

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

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

UTF‐16, урожденная UCS‐2 Curse

Как и некоторые другие языки, Javascript страдает от UTF-16 Curse. За исключением того, что 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));

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

Другие вопросы по тегам