Как узнать, содержит ли конкретная строка символы Юникода (особенно двухбайтовые символы) - PullRequest
26 голосов
/ 29 сентября 2008

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

Ответы [ 6 ]

34 голосов
/ 08 ноября 2009

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

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

у меня работает :) 1007 *

27 голосов
/ 29 сентября 2008

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;
}

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

9 голосов
/ 13 октября 2017

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

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);
}

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

6 голосов
/ 29 сентября 2008

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

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

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

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

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

o = document.getElementById("test");

document.defaultView.getComputedStyle(o,"").getPropertyValue("height"))
2 голосов
/ 22 ноября 2018

Вот эталонный тест: http://jsben.ch/NKjKd

Это намного быстрее:

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

чем это:

function isDoubleByte(str) {
    for (var i = 0, n = str.length; i < n; i++) {
        if (str.charCodeAt( i ) > 255) { return true; }
    }
    return false;
}
0 голосов
/ 29 сентября 2008

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

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

window.resizeTo(document.body.clientWidth, document.body.clientHeight);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...