Как я могу построить символ UTF-16 в JavaScript из суррогатной пары? - PullRequest
2 голосов
/ 20 февраля 2020

Далее вычисляется суррогатная пара UTF-16 для кодовой точки Unicode ( Face with Medical Mask ).

Но как я могу затем построить символ из суррогатной пары для использования в строке?

const codepoint = 0b11111011000110111 // ?
const tmp = codepoint - 0x10000
const padded = tmp.toString(2).padStart(20, '0')
const unit1 = (Number.parseInt(padded.substr(0, 10), 2) + 0xD800).toString(16)
const unit2 = (Number.parseInt(padded.substr(10), 2) + 0xDC00).toString(16)

// obviously hard-coding the values works...
console.log(`Hard-coded: \ud83d\ude37`)
// ...but how to combine unit1 and unit2 to print the character?
console.log(`Dynamic: unit1: ${unit1}, unit2: ${unit2}`)

1 Ответ

3 голосов
/ 20 февраля 2020

Два ответа для вас:

Возможно, вам не придется

В современной среде JavaScript вам не нужно разбивать код на части, вы можете использовать String.fromCodePoint чтобы создать персонажа напрямую:

const ch = String.fromCodePoint(codepoint);

Live Пример:

const codepoint = 0b11111011000110111; // ?
const ch = String.fromCodePoint(codepoint);

console.log(ch);

Вы можете построить его из частей

Если у вас нет fromCodePoint или у вас есть суррогаты в качестве отправной точки, вы можете получить строковая версия каждого суррогата через fromCharCode - но не делайте toString(16), оставьте единицы в виде чисел:

const unit1 = Number.parseInt(padded.substr(0, 10), 2) + 0xD800;
const unit2 = Number.parseInt(padded.substr(10), 2) + 0xDC00;

const ch = String.fromCharCode(unit1, unit2);

Live Пример:

const codepoint = 0b11111011000110111 // ?
const tmp = codepoint - 0x10000
const padded = tmp.toString(2).padStart(20, '0')
const unit1 = Number.parseInt(padded.substr(0, 10), 2) + 0xD800;
const unit2 = Number.parseInt(padded.substr(10), 2) + 0xDC00;

const ch = String.fromCharCode(unit1, unit2);

console.log(ch);

Вы даже можете сделать это как

const ch = String.fromCharCode(unit1) + String.fromCharCode(unit2);

... но поскольку fromCharCode принимает несколько кодов символов (кодовых единиц), это, вероятно, делает больше смысла передавать им оба сразу.

Тот факт, что он работает с каждым в отдельности (String.fromCharCode(unit1) + String.fromCharCode(unit2)), может показаться очень, очень странным. "Вы имеете в виду, что String.fromCharCode счастливо создает строку с половиной суррогатной пары ?!" Ага. :-) JavaScript строки являются последовательностями кодовых единиц UTF-16 , но они допускают недопустимые или потерянные суррогатные пары. Начиная с spe c:

Тип String - это набор всех упорядоченных последовательностей от нуля или более 16-разрядных целочисленных значений без знака («элементов») до максимальная длина 2 53 - 1 элемент. Тип String обычно используется для представления текстовых данных в работающей программе ECMAScript, и в этом случае каждый элемент в String обрабатывается как значение кодовой единицы UTF-16. ...

Операции ECMAScript, которые не интерпретируют содержимое строки, не применяют никакой семантики. Операции, которые интерпретируют строковые значения, обрабатывают каждый элемент как одну кодовую единицу UTF-16. Однако ECMAScript не ограничивает значение или отношения между этими единицами кода , поэтому операции, которые дополнительно интерпретируют содержимое строки как последовательности кодовых точек Unicode, закодированных в UTF-16, должны учитывать неправильно сформированные подпоследовательности. ...

(мой акцент)

...