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

StackOverflow https://stackoverflow.com/questions/147824

  •  02-07-2019
  •  | 
  •  

Вопрос

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

Это было полезно?

Решение

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

Возможно, это будет не так быстро, как вам хотелось бы.

Другие советы

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

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

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

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

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 раза быстрее.

Однако обратите внимание, что для строки, в которой первый символ имеет кодировку Unicode, 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);
}

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

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

К сожалению, простого присутствия символов в определенном диапазоне Юникода недостаточно, чтобы определить, что вам нужно больше места.Существует ряд символов, которые занимают примерно столько же места, сколько и другие символы, коды которых в Юникоде значительно превышают диапазон 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"))

Вот эталонный тест: 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;
}

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

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

window.resizeTo(document.body.clientWidth, document.body.clientHeight);
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top