Юникод символы из кода в javascript для кодов> 0xFFFF
Мне нужно получить строку / символ из кода Юникода и, наконец, поместить его в текстовый узел DOM, чтобы добавить на страницу HTML с помощью клиентского JavaScript.
В настоящее время я занимаюсь:
String.fromCharCode(parseInt(charcode, 16));
где charcode
шестнадцатеричная строка, содержащая код, например "1D400"
, Символ Unicode, который должен быть возвращен , но
퐀
возвращается! Символы в 16-битном диапазоне (0000
... FFFF
) возвращаются, как и ожидалось.
Любое объяснение и / или предложения по исправлению?
Заранее спасибо!
3 ответа
Проблема в том, что символы в 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]) );
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);
}
}
Раздел 8.4 спецификации языка EcmaScript говорит
Когда строка содержит фактические текстовые данные, каждый элемент считается одной кодовой единицей UTF-16. Независимо от того, является ли это фактическим форматом хранения String, символы в String нумеруются по их начальной позиции элемента кода, как если бы они были представлены с использованием 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) === ''
String.fromCodePoint()
кажется, делает свое дело тоже. Смотрите здесь
console.log(String.fromCodePoint(0x1D622, 0x1D623, 0x1D624, 0x1D400));
Выход: