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

Javascript RegExp + границы Word + символы Unicode

Я создаю поиск, и я собираюсь использовать с ним javascript autocomplete. Я из Финляндии (финский язык), поэтому мне приходится иметь дело с некоторыми специальными персонажами, такими как ä, ö и å

Когда пользователь вводит текст в поле ввода поиска, я пытаюсь сопоставить текст с данными.

Вот простой пример, который работает некорректно, если пользователь вводит, например, "ää". То же самое с "äl"

var title = "this is simple string with finnish word tämä on ääkköstesti älkää ihmetelkö";
// Does not work
var searchterm = "äl";

// does not work
//var searchterm = "ää";

// Works
//var searchterm = "wi";

if ( new RegExp("\\b"+searchterm, "gi").test(title) ) {
    $("#result").html("Match: ("+searchterm+"): "+title);
} else {
    $("#result").html("nothing found with term: "+searchterm);   
}

http://jsfiddle.net/7TsxB/

Итак, как я могу заставить эти символы ä, ö и å работать с регулярным выражением javascript?

Я думаю, что я должен использовать коды Юникода, но как мне это сделать? Кодами для этих символов являются: [\ U00C4,\u00E4,\u00C5,\u00E5,\u00D6,\u00F6]

= > äÄåÅÖÖ

4b9b3361

Ответ 1

Кажется, что проблема с Regex и границей слов \b соответствует началу строки с начальным символом из нормального диапазона в 256 байт.

Вместо использования \b попробуйте использовать (?:^|\\s)

var title = "this is simple string with finnish word tämä on ääkköstesti älkää ihmetelkö";
// Does not work
var searchterm = "äl";

// does not work
//var searchterm = "ää";

// Works
//var searchterm = "wi";

if ( new RegExp("(?:^|\\s)"+searchterm, "gi").test(title) ) {
    $("#result").html("Match: ("+searchterm+"): "+title);
} else {
    $("#result").html("nothing found with term: "+searchterm);   
}

Структура:

(?: скобка () формирует группу захвата в Regex. Скобка начинается с вопросительного знака, а двоеточие ?: формирует группу, не связанную с захватом. Они просто группируют термины вместе

^ символ каретки соответствует началу строки

| бар является оператором "или".

\s соответствует пробелу (отображается как \\s в строке, потому что нам нужно избежать обратного слэша)

) закрывает группу

Поэтому вместо использования \b, который соответствует границам слов и не работает для символов Unicode, мы используем группу, не связанную с захватом, которая соответствует началу строки ИЛИ пробела.

Ответ 2

Класс символов \b в JavaScript RegEx действительно полезен только при простой кодировке ASCII. \b - это код быстрого доступа для границы между \w и \w наборами или \w и началом или концом строки. Эти наборы символов учитывают только слова ASCII "word", где \w равно [a-zA-Z0-9_], а \w - отрицание этого класса.

Это делает классы символов RegEx бесполезными для работы с любым реальным языком.

\s должен работать для того, что вы хотите сделать, при условии, что условия поиска ограничиваются только пробелами.

Ответ 3

этот вопрос старый, но я думаю, что нашел лучшее решение для границы в регулярных выражениях с символами unicode. Используя XRegExp, вы можете реализовать допустимую границу \b, расширяющую этот

XRegExp('(?=^|$|[^\\p{L}])')

результат длится 4000+ char, но, похоже, он работает довольно эффективно.

Некоторое объяснение: (? =) представляет собой просмотр с нулевой длиной, который ищет начальную или конечную границу или небуквенный символ юникода. Самое важное - это взгляд, потому что \b ничего не захватывает: он просто истинный или ложный.

Ответ 4

Я бы рекомендовал вам использовать XRegExp, когда вам нужно работать с определенным набором символов из Unicode, автором этой библиотеки отображает все виды региональных наборов символов, облегчая работу с разными языками.

Ответ 5

Я заметил что-то действительно странное с \b при использовании Unicode:

/\bo/.test("pop"); // false (obviously)
/\bä/.test("päp"); // true (what..?)

/\Bo/.test("pop"); // true
/\Bä/.test("päp"); // false (what..?)

Похоже, что значение \b и \b отменено, но только при использовании с Unicode без ASCII? Здесь может быть что-то более глубокое, но я не уверен, что это такое.

В любом случае кажется, что проблема заключается в границе слова, а не в символах Юникода. Возможно, вам нужно просто заменить \b на (^|[\s\\/-_&]), поскольку это работает правильно. (Сделайте свой список символов более всеобъемлющим, чем мой.)

Ответ 6

Моя идея - поиск с кодами, представляющими финские буквы

new RegExp("\\b"+asciiOnly(searchterm), "gi").test(asciiOnly(title))

Моя первоначальная идея состояла в том, чтобы использовать plain encodeURI, но знак%, похоже, мешал регулярному выражению.

http://jsfiddle.net/7TsxB/5/

Я написал грубую функцию, использующую encodeURI для кодирования каждого символа с кодом более 128, но удаление его% и добавление "QQ" в начале. Это не лучший маркер, но я не мог заставить не буквенно-цифровые работать.

Ответ 7

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

var text = "Ještě. že; \"už\" à. Fürs, 'anlässlich' že že že.";
var terms = ["à","anlässlich","Fürs","už","Ještě", "že"];
var replaced = [];
var order = 0;
for (i = 0; i < terms.length; i++) {
    terms[i] = "(^\|[ \n\r\t.,;'\"\+!?-])(" + terms[i] + ")([ \n\r\t.,;'\"\+!?-]+\|$)";
}
var re = new RegExp(terms.join("|"), "");
while (true) {
    var replacedString = "";
    text = text.replace(re, function replacer(match){
        var beginning = match.match("^[ \n\r\t.,;'\"\+!?-]+");
        if (beginning == null) beginning = "";
        var ending = match.match("[ \n\r\t.,;'\"\+!?-]+$");
        if (ending == null) ending = "";
        replacedString = match.replace(beginning,"");
        replacedString = replacedString.replace(ending,"");
        replaced.push(replacedString);
        return beginning+"{{"+order+"}}"+ending;
    });
if (replacedString == "") break;
order += 1;
}

Смотрите код в скрипте: http://jsfiddle.net/antoninslejska/bvbLpdos/1/

Регулярное выражение вдохновлено: http://breakthebit.org/post/3446894238/word-boundaries-in-javascripts-regular

Я не могу сказать, что я нахожу решение элегантным...