Ленивое регулярное выражение не работает, как ожидалось C # - PullRequest
3 голосов
/ 21 июня 2010

У меня есть следующее регулярное выражение: a?\W*?b, и у меня есть строка ,.! ,b
При поиске совпадения я получаю ,.! ,b, но не просто b, как я ожидаю.Это почему?Как изменить регулярное выражение, чтобы получить то, что мне нужно?
Спасибо за вашу помощь.

Ответы [ 7 ]

4 голосов
/ 21 июня 2010

Ленивый квантификатор здесь не поможет тому, что вы хотите. Посмотрим, что происходит.

Движок регулярных выражений запускается в начале строки. Сначала пытается соответствовать a. Это невозможно, но это не проблема, поскольку a является необязательным.

Затем, есть ленивый \W*?, поэтому механизм регулярных выражений пропускает его, но запоминает текущую позицию.

Затем он пытается сопоставить b. Он не может, поэтому он возвращается и успешно сопоставляет , с \W*?. Затем он продолжает пытаться сопоставить b (из-за ленивого квантификатора). Это все еще не может и возвращается назад. Это повторяется несколько раз, пока, наконец, двигатель регулярных выражений не достигнет b. Теперь совпадение завершено - механизм регулярных выражений объявляет об успехе.

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

Например, если вы действительно хотите:

Совпадение b в одиночку, если ему не предшествует a и некоторые несловарные символы, в этом случае сопоставьте все от a до b, затем используйте

b|a\W*b
1 голос
/ 21 июня 2010

Ленивое выражение только лениво справа, т.е. оно будет настолько коротким, насколько это возможно, удаляя символы справа, но оно не будет удалять символы слева.

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

В качестве альтернативы, как показал Тим, вы можете начать сравнение позже, сопоставив только первый символ и следующие разделителиесли существует первый символ.

0 голосов
/ 21 июня 2010

Ошибочно говорить о регулярном выражении как о жадном или не жадном. Вы можете использовать не жадные квантификаторы по всему регулярному выражению, но он все равно попытается начать сопоставление при первой же возможности, как вы обнаружили. Аналогично, регулярное выражение, использующее только жадные квантификаторы, не гарантирует возвращение самого длинного возможного соответствия. Например,

Regex.Match("foo bar", @"\w+ (?:b|bar)")

... возвращает foo b, потому что чередование устанавливает первую альтернативу, которая работает, даже если более поздняя приведет к более длинному совпадению. (Обратите внимание, что я имею в виду производные от Perl разновидности regex, такие как .NET; некоторые разновидности, такие как awk и egrep, действительно выдерживают самое длинное совпадение. Но, поскольку эти разновидности не жадные квантификаторы, жадные алгоритмы - не просто режим по умолчанию, это режим only .)

Короче говоря, нет такого понятия, как жадное или не жадное регулярное выражение, только жадные или не жадные квантификаторы.

0 голосов
/ 21 июня 2010

Ваш пример не показывает, почему a? является частью вашего регулярного выражения, но чтобы соответствовать только b в строке, которая выглядит как ,.! ,b, вы можете использовать lookbehind как это (?=\W*?)b.

Это соответствует b, которому предшествует символ, который является "несловесным символом" ноль и неограниченное количество раз (как можно меньше)

Если вы хотите сопоставить, скажем, a и b в такой строке, как a,.! ,b, вам придется использовать группы захвата: (a?)\W*?(b), где первая группа будет содержать a, если она присутствует, и группу 2 b

0 голосов
/ 21 июня 2010

a? говорит "я хочу либо ноль, либо один экземпляр a" - это удовлетворяется, поскольку существует ноль экземпляров, после чего следует

\W* говорит "я хочу ноль или более не состоящих из слов символов" , что удовлетворяется знаками препинания и пробела, и, наконец,

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

Будет полезно, если вы приведете больше примеров возможных входных данных, прежде чем кто-либо предложит возможное решение.

0 голосов
/ 21 июня 2010

Ваше регулярное выражение соответствует всей строке следующим образом:

  1. a, ноль или одно повторение (в данном случае "")
  2. Любой символ, который не является буквенно-цифровым, любое числоповторений, как можно меньше (",.!," в этом случае)
  3. b

В вашем случае регулярное выражение соответствует всей строке и поэтому не найдет толькоb (он не находит несколько совпадений для одной и той же части).

Если вы ищете строку типа ',.!, дБ 'он найдет б.

0 голосов
/ 21 июня 2010

Например, может сработать следующее: (a\W*)?b

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

...