Регулярное выражение с необязательной частью не создает обратную ссылку - PullRequest
1 голос
/ 09 июня 2010

Я хочу сопоставить необязательный тег в конце строки текста.

Пример ввода текста:

The quick brown fox jumps over the lazy dog {tag}

Я хочу сопоставить деталь в фигурных скобках и создатьобратная ссылка на него.

Мое регулярное выражение выглядит так:

^.*(\{\w+\})?

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

Этосоответствует строкам в порядке (с тегом и без), но не создает обратную ссылку на тег.

Если я уберу '?'символ, поэтому регулярное выражение:

^.*(\{\w+\})

Создает обратную ссылку на тег, но затем не сопоставляет строки без тега.

Я понял из http://www.regular-expressions.info/refadv.html, что дополнительный оператор не повлияет на обратную ссылку:

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

, но, должно быть, что-то неправильно поняли.*

Как сделать часть тега необязательной и создать обратную ссылку, когда она существует?

Ответы [ 5 ]

3 голосов
/ 09 июня 2010

Это не проблема обратной ссылки, проблема в том, что регулярное выражение было удовлетворено простым чтением в тексте, который соответствует .*.Не было необходимости продолжать чтение, чтобы прочитать дополнительный конечный тег.Самое простое решение, если вы действительно читаете до конца строки, это добавить $ (знак доллара), чтобы регулярное выражение совпадало со всей строкой.

edit

Кстати, я не воспринимал ваш reg-ex буквально, так как вы сказали, что он соответствует другим вещам, но просто для ясности .* будет занимать всю строку.Вам нужно что-то вроде [^{]*, чтобы предотвратить проглатывание тега.Я полагаю, это не проблема для вас.

2 голосов
/ 09 июня 2010

В дополнение к тому, что объяснили другие, вы можете сделать .* "ленивым":

^.*?(\{\w+\})?
1 голос
/ 09 июня 2010

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

^.*?(\{\w+\})?$ 

Я не хотел использовать [^ {] * для первой части совпадения, поскольку здесь могут отображаться фигурные скобки без тегов, но теги всегда будут в конце строки.

Спасибо за ответы, все они были полезны.

1 голос
/ 09 июня 2010

Как сказал Дэвид Гладфелтер, реальная проблема в том, что когда вы делаете его необязательным, он не совпадает с ;однако предложенное им исправление не сработает . Правка 1: Вам нужно будет использовать то, что он вложил в свою правку (которая была написана, когда я писал это).Проблема в том, что квантификаторы (*, +, ?, {n,m}) жадные : они всегда совпадают настолько, насколько возможно.Таким образом, когда вы пишете ^.*(\{\w+\})?, .* всегда будет соответствовать всей строке, потому что пустое соответствие удовлетворяет необязательной группе.Также обратите внимание, что хотя ? является жадным, первая жадность (из .*) имеет приоритет.Если вам разрешено иметь только фигурные скобки вокруг этой необязательной группы, то вы можете решить свою проблему, прямо сказав: ^[^\{]*(\{\w+\})?.Таким образом, первый фрагмент будет соответствовать всему, вплоть до первой фигурной скобки, а затем (так как ? является жадным), если это возможно, соответствовать слову в фигурных скобках.

Зачастую другой способ решить эту проблемучтобы сделать квантификаторы ленивыми (или не жадными, минимальными и т. д.), добавив ?: *?, +?, ?? и {n,m}?.Однако это вам здесь не поможет: вместо этого, если вы сделаете ^.*?(\{\w+\})?, ленивый .*? попытается сопоставить ноль символов, успешно, а затем необязательная группа не будет соответствовать.Тем не менее, хотя это не сработает, это полезный инструмент в вашем наборе инструментов. Edit 1: Также обратите внимание, что они доступны не во всех движках регулярных выражений, хотя они доступны в C #.

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

Если вас интересует только тег, и вас не волнует остальная часть строки, то вы значительно упростите свою жизнь, просто сопоставив тег с этим регулярным выражением ( см. Его на Rubular.com ):

\{(\w+)\}$

То есть, вы пытаетесь сопоставить некоторые {word} в конце строки.Если его там нет, то тоже плохо, там нет совпадений.Нет необходимости в модификаторе ? или неохотном .* и всем этом.

В C # вы можете даже захотеть использовать RegexOptions.RightToLeft, так как вы все равно пытаетесь сопоставить суффикстак что, возможно, что-то вроде этого:

string[] lines = {
  "The quick brown fox jumps over the lazy dog",
  "The quick brown fox jumps over the lazy dog {tag}",
  "The quick brown fox jumps over the {lazy} dog",
  "The quick brown fox jumps over the {lazy} {dog}",
};

Regex r = new Regex(@"\{(\w+)\}$", RegexOptions.RightToLeft);

foreach (string line in lines) {
  Console.WriteLine("[" + r.Match(line).Groups[1] + "]");
}

Это печатает ( как видно на ideone.com ):

[]
[tag]
[]
[dog]
...