Подтвердить что ты не робот

Unicode символы из charcode в javascript для charcodes> 0xFFFF

Мне нужно получить строку / char из кодировки unicode и, наконец, поместить его в DOM TextNode для добавления в HTML-страницу с использованием JavaScript на стороне клиента.

В настоящее время я делаю:

String.fromCharCode(parseInt(charcode, 16));

где charcode - это шестнадцатеричная строка, содержащая символ, например. "1D400". Символ unicode, который должен быть возвращен, равен 𝐀, но возвращается ! Символы в 16-битном диапазоне (0000... FFFF) возвращаются, как ожидалось.

Любое объяснение и/или предложения по исправлению?

Спасибо заранее!

4b9b3361

Ответ 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) === '𐐀'