Страницы

Поиск по вопросам

пятница, 10 января 2020 г.

Поиск перекрестных совпадений с помощью регулярных выражений

#c_sharp #регулярные_выражения


Добрый вечер. Понимаю, что вопрос очень глупый, но голова уже не варит. Да, начинается
время зачетов :)
Для N-ной лабы по матстату нужно посчитать количество вхождений подстроки в строку.
Банальщина. Чтобы эту банальщину хоть как-то приукрасить, пишем extension method для
string:
public static int P(this string baseStr, string inputStr)
{
    return new Regex(inputStr).Matches(baseStr).Count;
}

Для справки - в задании строка из N 0 и 1, первым этапом надо посчитать вероятности
появления пар в строке. 
Собственно, мой глупый вопрос: почему описанный метод, вызванный от строки "1111"
возвращает 2? Ну не могут же регулярки последовательно считать...
UPD:
пример вызова метода:
string data = "1111";
Console.WriteLine(data.P("11")); //2
    


Ответы

Ответ 1



Всё верно: в строке 1111 всего два вхождения подстроки 11. Регулярные выражения анализируют текст слева направо. При совпадении внутренний "курсор" (индекс) устанавливается на его начальную позицию. Следущее совпадение система начинает искать с позиции, находящейся сразу после текущего совпадения. Таким образом, перекрёстные совпадения невозможны при использовании обычных шаблонов. Как верно заметил ReinRaus, необходимо воспользоваться механизмом опережающей проверки, т.е. конструкцией (?=...), которая используется для проверки того, что следует после текущей позиции в строке. Несмотря на то, что такие блоки не "поглощают" текст при совпадении (т.е. при нахождении подстроки индекс остаётся на прежнем месте во входной строке), внутри них возможно использование захватывающих подмасок типа (...). Тут мы подходим к решению проблемы: string data = "1111"; string sub = "11"; Console.WriteLine(data.P(string.Format("(?=({0}))", Regex.Escape(sub))); Здесь пример использования данного подхода.

Ответ 2



Потому что вхождения не могут пересекаться. Надо делать предпросмотр, чтобы сжирать только то, что не входит в искомую строку: (?=11)

Комментариев нет:

Отправить комментарий