Юникод символы из кода в 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));

Выход:


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