Unicode символы из charcode в javascript для charcodes> 0xFFFF
Мне нужно получить строку / char из кодировки unicode и, наконец, поместить его в DOM TextNode для добавления в HTML-страницу с использованием JavaScript на стороне клиента.
В настоящее время я делаю:
String.fromCharCode(parseInt(charcode, 16));
где charcode
- это шестнадцатеричная строка, содержащая символ, например. "1D400"
. Символ unicode, который должен быть возвращен, равен 𝐀
, но возвращается 퐀
! Символы в 16-битном диапазоне (0000
... FFFF
) возвращаются, как ожидалось.
Любое объяснение и/или предложения по исправлению?
Спасибо заранее!
Ответы
Ответ 1
Проблема состоит в том, что символы в JavaScript (в основном) кодируются UCS-2, но могут представлять символ за пределами базовой многоязычной плоскости в JavaScript как суррогатная пара UTF-16.
Следующая функция адаптирована из Преобразование punycode с тире символа в Unicode:
function utf16Encode(input) {
var output = [], i = 0, len = input.length, value;
while (i < len) {
value = input[i++];
if ( (value & 0xF800) === 0xD800 ) {
throw new RangeError("UTF-16(encode): Illegal UTF-16 value");
}
if (value > 0xFFFF) {
value -= 0x10000;
output.push(String.fromCharCode(((value >>>10) & 0x3FF) | 0xD800));
value = 0xDC00 | (value & 0x3FF);
}
output.push(String.fromCharCode(value));
}
return output.join("");
}
alert( utf16Encode([0x1D400]) );
Ответ 2
String.fromCharCode может обрабатывать только кодовые точки в BMP (то есть до U + FFFF). Для обработки более высоких кодовых точек эта функция из Mozilla Developer Network может использоваться для возврата суррогатного представления пары:
function fixedFromCharCode (codePt) {
if (codePt > 0xFFFF) {
codePt -= 0x10000;
return String.fromCharCode(0xD800 + (codePt >> 10), 0xDC00 + (codePt & 0x3FF));
} else {
return String.fromCharCode(codePt);
}
}
Ответ 3
В разделе 8.4 спецификации языка EcmaScript указано
Когда строка содержит фактические текстовые данные, каждый элемент считается единым модулем кода UTF-16. Независимо от того, является ли это фактическим форматом хранения строки, символы внутри строки нумеруются по их исходной позиции элемента кода, как если бы они были представлены с использованием UTF-16. Все операции над строками (кроме как указано иначе) рассматривают их как последовательности недифференцированных 16-разрядных целых без знака; они не гарантируют, что результирующая Строка находится в нормализованной форме, и они не гарантируют языковых результатов.
Итак, вам нужно кодировать дополнительные кодовые точки в виде пар кодов UTF-16.
В статье "Дополнительные символы в платформе Java" дается хорошее описание того, как это сделать.
UTF-16 использует последовательности одного или двух беззнаковых 16-разрядных кодовых блоков для кодирования кодовых точек Unicode. Значения U + 0000 - U + FFFF кодируются в одном 16-битном блоке с тем же значением. Дополнительные символы кодируются в двух кодовых единицах, первый из диапазона высоких суррогатов (U + D800 - U + DBFF), второй из диапазона низких суррогатов (U + DC00 - U + DFFF). Это может показаться схожим в концепции с многобайтовыми кодировками, но существует важное различие: значения U + D800 - U + DFFF зарезервированы для использования в UTF-16; никакие символы не назначаются им как кодовые точки. Это означает, что программное обеспечение может указывать для каждого отдельного блока кода в строке, является ли он символом одного элемента или является ли он первым или вторым блоком символа с двумя единицами. Это значительное улучшение по сравнению с некоторыми традиционными многобайтовыми кодировками символов, где значение байта 0x41 может означать букву "A" или быть вторым байтом двухбайтового символа.
В следующей таблице показаны различные представления нескольких символов в сравнении:
кодовые точки/кодовые единицы UTF-16
U + 0041/0041
U + 00DF/00DF
U + 6771/6771
U + 10400/D801 DC00
Как только вы знаете кодовые единицы UTF-16, вы можете создать строку, используя функцию javascript String.fromCharCode
:
String.fromCharCode(0xd801, 0xdc00) === '𐐀'