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

Как определить, имеет ли конкретная строка символы Юникода (особенно двойные байтовые символы)

Чтобы быть более точным, мне нужно знать, может ли (и, если возможно, как) определить, имеет ли данная строка двухбайтовые символы или нет. В принципе, мне нужно открыть всплывающее окно, чтобы отобразить данный текст, который может содержать двухбайтовые символы, такие как китайский или японский. В этом случае нам нужно настроить размер окна, чем для английского или ASCII. Кто-нибудь знает?

4b9b3361

Ответ 1

JavaScript хранит текст внутри себя как UCS-2, который может кодировать довольно обширное подмножество Unicode.

Но это на самом деле не связано с вашим вопросом. Одним из решений может быть цикл через строку и проверка кодов символов в каждой позиции:

function isDoubleByte(str) {
    for (var i = 0, n = str.length; i < n; i++) {
        if (str.charCodeAt( i ) > 255) { return true; }
    }
    return false;
}

Это может быть не так быстро, как хотелось бы.

Ответ 2

Я использовал mikesamuel ответ на этот. Однако я заметил, возможно, из-за этой формы, что перед u должна быть только одна слэш-слэш. \u, а не \\u, чтобы сделать эту работу правильно.

function containsNonLatinCodepoints(s) {
    return /[^\u0000-\u00ff]/.test(s);
}

Работает для меня:)

Ответ 3

Собственно, все символы являются Unicode, по крайней мере, с точки зрения Javascript.

К сожалению, простого присутствия символов в определенном диапазоне Unicode недостаточно, чтобы определить, что вам нужно больше места. Существует несколько символов, которые занимают примерно столько же места, что и другие символы, которые имеют кодовые обозначения Unicode, значительно превышающие диапазон ASCII. Типографические кавычки, символы с диакритикой, некоторые символы пунктуации и различные символы валюты находятся за пределами диапазона низких ASCII и распределены в совершенно разрозненных местах на базовой многоязычной плоскости Unicode.

Как правило, проекты, над которыми я работал над избранными, предоставляют дополнительное пространство для всех языков или иногда используют javascript для определения того, имеет ли окно с атрибутами CSS с автоматической прокруткой фактическое содержание с высотой, которая запускает полосу прокрутки или нет.

Если обнаружение присутствия или количество символов CJK будет достаточным, чтобы определить, что вам нужно немного лишнего пространства, вы можете создать регулярное выражение, используя следующие диапазоны: [\ u3300-\u9fff\uf900-\ufaff], и используйте это для извлечения количества совпадающих символов. (Это немного чрезмерно грубый и пропускает все случаи, отличные от BMP, вероятно, исключает некоторые другие соответствующие диапазоны и, скорее всего, включает в себя некоторые нерелевантные символы, но это отправная точка).

Опять же, вы сможете справиться с грубой эвристикой, не имея ничего общего с движком полного текстового рендеринга, потому что то, что вы действительно хотите, это что-то вроде GDI MeasureString (или любого другого эквивалента для рендеринга текста). Прошло некоторое время с тех пор, как я это сделал, но я думаю, что ближайший эквивалент HTML/DOM устанавливает ширину в div и запрашивает высоту (повторное использование вырезания и вставки, поэтому извиняюсь, если это содержит ошибки):

o = document.getElementById("test");

document.defaultView.getComputedStyle(o,"").getPropertyValue("height"))

Ответ 4

Я проверил две функции в верхних ответах и ​​подумал, что буду делиться результатами. Вот тестовый код, который я использовал:

const text1 = `The Chinese Wikipedia was established along with 12 other Wikipedias in May 2001. 中文維基百科的副標題是「海納百川,有容乃大」,這是中国的清朝政治家林则徐(1785年-1850年)於1839年為`;

const regex = /[^\u0000-\u00ff]/; // Small performance gain from pre-compiling the regex
function containsNonLatinCodepoints(s) {
    return regex.test(s);
}

function isDoubleByte(str) {
    for (var i = 0, n = str.length; i < n; i++) {
        if (str.charCodeAt( i ) > 255) { return true; }
    }
    return false;
}

function benchmark(fn, str) {
    let startTime = new Date();
    for (let i = 0; i < 10000000; i++) {
        fn(str);
    }   
    let endTime = new Date();

    return endTime.getTime() - startTime.getTime();
}

console.info('isDoubleByte => ' + benchmark(isDoubleByte, text1));
console.info('containsNonLatinCodepoints => ' + benchmark(containsNonLatinCodepoints, text1));

При выполнении этого я получил:

isDoubleByte => 2421
containsNonLatinCodepoints => 868

Итак, для этой конкретной строки решение регулярного выражения примерно в 3 раза быстрее.

Однако обратите внимание, что для строки, где первый символ является юникодом, isDoubleByte() возвращает сразу и, следовательно, намного быстрее, чем регулярное выражение (которое все еще имеет накладные расходы регулярного выражения).

Например, для строки 中国 я получил следующие результаты:

isDoubleByte => 51
containsNonLatinCodepoints => 288

Чтобы получить лучшее от мира, возможно, лучше комбинировать оба:

var regex = /[^\u0000-\u00ff]/; // Small performance gain from pre-compiling the regex
function containsDoubleByte(str) {
    if (!str.length) return false;
    if (str.charCodeAt(0) > 255) return true;
    return regex.test(str);
}

В этом случае, если первым символом является китайский (что, вероятно, весь текст является китайским), функция будет быстрой и сразу вернется. Если нет, он запустит регулярное выражение, которое все же будет быстрее, чем проверка каждого символа в отдельности.

Ответ 5

Почему бы не позволить самому размеру окна на основе высоты/ширины выполнения?

Запустите что-то подобное в своем всплывающем окне:

window.resizeTo(document.body.clientWidth, document.body.clientHeight);