Как я могу узнать, содержит ли строка многобайтовые символы в Javascript? - PullRequest
19 голосов
/ 02 февраля 2011

Возможно ли в Javascript обнаружить, содержит ли строка многобайтовые символы?Если да, то можно ли сказать, какие из них?

Проблема, с которой я сталкиваюсь, заключается в следующем (извиняюсь, если символ Unicode не подходит именно вам)

s = "?";

alert(s.length);    // '2'
alert(s.charAt(0)); // '��'
alert(s.charAt(1)); // '��'

Отредактируйте для большей ясности здесь (я надеюсь) . Как я понимаю сейчас , все строки в Javascript представлены в виде последовательности UTF-16 кодовых точек, что означает, что обычные символы на самом деле занимают 2 байта (16 бит), поэтому мое использование «многобайтовых» в заголовке было немного неправильным.Некоторые символы не попадают в базовую многоязычную плоскость (BMP), например строку в примере выше, и поэтому они занимают две кодовые точки (32 бита).Это вопрос, который я задавал.Я также не редактирую оригинальное название, поскольку для кого-то, кто мало знает об этом материале (и, следовательно, будет искать информацию о нем в SO), "multibyte" будет иметь смысл.

1 Ответ

26 голосов
/ 03 февраля 2011

Строки JavaScript кодируются UCS-2, но могут представлять кодовые точки Unicode вне базовой многоязычной панели (U+0000 - U+D7FF и U+E000 - U+FFFF) с использованием двух 16-битных чисел (UTF-16 * 1005).* суррогатная пара ), первая из которых должна находиться в диапазоне U+D800 - U+DFFF.

Исходя из этого, легко определить, содержит ли строка какие-либо символы, лежащие за пределами BasicМногоязычная плоскость (о чем я думаю, вы спрашиваете: вы хотите иметь возможность определить, содержит ли строка какие-либо символы, лежащие за пределами диапазона кодовых точек, которые JavaScript представляет как один символ):

function containsSurrogatePair(str) {
    return /[\uD800-\uDFFF]/.test(str);
}

alert( containsSurrogatePair("foo") ); // false
alert( containsSurrogatePair("f?") ); // true

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

var getStringCodePoints = (function() {
    function surrogatePairToCodePoint(charCode1, charCode2) {
        return ((charCode1 & 0x3FF) << 10) + (charCode2 & 0x3FF) + 0x10000;
    }

    // Read string in character by character and create an array of code points
    return function(str) {
        var codePoints = [], i = 0, charCode;
        while (i < str.length) {
            charCode = str.charCodeAt(i);
            if ((charCode & 0xF800) == 0xD800) {
                codePoints.push(surrogatePairToCodePoint(charCode, str.charCodeAt(++i)));
            } else {
                codePoints.push(charCode);
            }
            ++i;
        }
        return codePoints;
    }
})();

alert( getStringCodePoints("f?").join(",") ); // 102,119558
...