Страницы

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

суббота, 14 декабря 2019 г.

Сделать универсальное регулярное выражение

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


Нужно сделать регулярное выражение, которое будет удалять предыдущий символ перед
текстом . Казалось бы, это реализуется очень просто:

str = Regex.Replace(str, @".", "");


Но тут есть подводные камни. Если, например, в тексте идет 2  подряд,
тогда конструкция рушится. Можно, конечно, сделать такое решение:

str = Regex.Replace(str, @".|..", "");


но это бред, ведь может быть и 10  подряд и надо будет удалить 10 предыдущих
символов. Как сделать универсальным это регулярное выражение?



Может быть такая строка:

string str = "это буудкает текстовыыфй
ткаукцекст";


В итоге должны получить:

"это будет тестовый текст"

    


Ответы

Ответ 1



Думаю, одной изящной регуляркой это не сделать. Я придумал следующее: Match m; do { m = Regex.Match(str, "."); str = str.Remove(m.Index, m.Length); } while (m.Success); В цикле находим и удаляем по одному вхождению паттерна. Конечно, этот способ не блещет производительностью.

Ответ 2



В .NET можно решить эту проблему регулярным выражением с проверкой состояния стека захватывающих групп: ^(?:)+|(?:(?(?))+(?(t)(?!))(?:)* См. демо регулярного выражения. Подробности ^(?:)+ - один и более последовательностей символов в начале строки (^) | - или (?:(?(?))+ - незахватывающая группа ((?:...)), находящая одну или более (+ — жадный квантификатор, находит 1 и более последовательных совпадений) последовательностей (?(?): (?(?) - одна и более последовательностей символов (при этом каждый раз при найденном совпадении из стека группы t будет удаляться последнее значение) (?(t)(?!)) - условная конструкция: если стек группы t не пуст, совпадение считается неверным, и запускается поиск с возвратом (backtracking), иначе возвращается совпадение (такое, где количество значений, найденных (?.) равно количеству значений, найденных (?<-t>)) (?:)* - ноль и более последовательностей символов Можно объявить это выражение в коде следующим образом: public static class Rx { public static readonly Regex backspaceRx = new Regex( @"^(?:)+ # 1+ в начале | # или (?: (?(?) # )+ # 1 или более раз (?(t)(?!)) # проверка стека группы t (?:)* # 0+ ", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace); } Тест на C#: var tests = new List {"это буудкает текстовыыфй ткаукцекст", "Это", "ab", "", "abcd" }; foreach(var test in tests) Console.WriteLine("'{0}'", Rx.backspaceRx.Replace(test, string.Empty)); Вывод: 'это будет тестовый текст' '' 'b' '' 'd'

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

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