Как отрисовать 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 в браузер?