Жадный вариант Regex действительно нужен? - PullRequest
2 голосов
/ 28 ноября 2009

Жадный вариант Regex действительно нужен?

Допустим, у меня есть следующие тексты, я люблю извлекать тексты из блоков [Optionx] и [/ Optionx]

[Option1]
Start=1
End=10
[/Option1]
[Option2]
Start=11
End=20
[/Option2]

Но с Regex Greedy Option, это даст мне

Start=1
End=10
[/Option1]
[Option2]
Start=11
End=20

Кому-нибудь это нужно? Если да, не могли бы вы дать мне знать?

Ответы [ 5 ]

7 голосов
/ 28 ноября 2009

Если я правильно понимаю, вопрос в том, почему (когда) вам нужно жадное сопоставление?

Ответ - почти всегда. Рассмотрим регулярное выражение, которое соответствует последовательности произвольных, но равных символов длиной не менее двух. Регулярное выражение будет выглядеть так:

(.)\1+

(\1 - это обратная ссылка, совпадающая с тем же текстом, что и первое выражение в скобках).

Теперь давайте выполним поиск повторов в следующей строке: abbbbbc. Что мы находим? Ну, если бы у нас не было жадного соответствия, мы нашли бы bb. Вероятно, не то, что мы хотим. Фактически, в большинстве приложений нам было бы интересно найти всю подстроку b s, bbbbb.

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

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

6 голосов
/ 28 ноября 2009

Регулярные выражения могут потенциально соответствовать нескольким частям текста.

Например, рассмотрим выражение (ab)*c+ и строку "abccababccc". Есть много частей строки, которые могут соответствовать регулярным выражениям:

   (abc)cababccc
   (abcc)ababccc
   abcc(ababccc)
   abccab(abccc)
   ab(c)cababccc
   ab(cc)ababccc
   abcabab(c)ccc
   ....

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

Существует множество возможных способов определения «победного матча». Наиболее распространенным является получение " самого длинного левого совпадения ", что приводит к жадному поведению, которое вы наблюдали.

Это типично для поиска и замены (а-ля grep), когда с a+ вы, вероятно, имеете в виду совпадение всего aaaa, а не одного a.

Выбор "кратчайшего непустого крайнего левого" совпадения - это обычное не жадное поведение. Это наиболее полезно, когда у вас есть разделители , как в вашем случае.

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

2 голосов
/ 29 ноября 2009

Еще одно соображение: во многих случаях жадные и не жадные квантификаторы приводят к одному и тому же совпадению, но отличаются по производительности:

С не жадным квантификатором движок регулярных выражений должен возвращаться после каждого сопоставленного символа до тех пор, пока он, наконец, не совпадет столько, сколько нужно. С другой стороны, с жадным квантификатором, он будет соответствовать максимально возможному «за один раз» и только затем откатывать столько, сколько необходимо для соответствия любым следующим токенам.

Допустим, вы применяете a.*c к abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbc. Это находит совпадение в 5 шагах движка регулярных выражений. Теперь примените a.*?c к той же строке. Совпадение идентично, но движку регулярных выражений требуется 101 шаг, чтобы прийти к такому выводу.

С другой стороны, если вы примените a.*c к abcbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, потребуется 101 шаг, тогда как a.*?c - только 5.

Так что, если вы знаете свои данные, вы можете настроить свое регулярное выражение так, чтобы оно максимально соответствовало им.

2 голосов
/ 28 ноября 2009

Если вы ищете текст между блоками optionx, вместо поиска. +, Ищите все, что не является "[\".

Это действительно грубо, но работает:

\[[^\]]+]([^(\[/)]+)

Первый бит ищет что-либо в квадратных скобках, затем второй бит ищет что-нибудь, кроме "[\". Таким образом, вам не нужно заботиться о жадности, просто скажите, что вы не хотите видеть.

1 голос
/ 28 ноября 2009

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

flag=0
open file for reading
for each line in file :
    if check "[/Option" in line:
        flag=0
    if check "[Option" in line:
        flag=1
        continue
    if flag:
        print line.strip()
        # you can store the values of each option in this part
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...