Запретить не жадной части потреблять следующую необязательную часть

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

<mandatory><non-greedy><optional><non-greedy>
Реализовано как:
^mandatory.*?(:?optionalpart)?.*?$

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

^mandatory.*?(:?findme(matchme))?.*?$

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


Пример: найти символ после 2, или найти пустую строку, если 2, нет, но обязательная часть совпадает.

"Foo: 2,b,1,a,3,c" -> match, $1 = "b"
"Foo: 1,a,2,b,3,c" -> match, $1 = "b"
"Foo: 1,a,3,c,2,b" -> match, $1 = "b"
"Foo: 2,b"         -> match, $1 = "b"
"Foo: 1,a,3,c"     -> match, $1 = ""
"Fuu: 1,a,2,b,3,c" -> no match.

Попытка 1: ^Foo: .*?(?:2,([a-z]))?.*?$
Во 2-м и 3-м примерах происходит сбой, возвращается "" вместо "2".

Попытка 2: ^Foo: .*?(?:2,([a-z])).*?$
Это исправляет предыдущий сбой, но теперь сбой в 5-м примере не соответствует.
Часть, которая должна быть необязательной, больше не является необязательной.

Если это имеет значение, я использую класс Pattern Java.

--

Об этом задавали раньше, но не было удовлетворительного ответа на любой из нас.


person Mark Jeronimus    schedule 14.11.2018    source источник


Ответы (1)


Ваше первое регулярное выражение очень близко, вам нужно переместить (?: немного левее, чтобы включить шаблон .*?:

^Foo:(?: .*?2,([a-z]))?.*$
     ^^^ 

См. демонстрацию регулярного выражения.

Подробнее

  • ^ - начало строки
  • Foo: - буквальный текст
  • (?: .*?2,([a-z]))? - an optional non-capturing group that matches greedily (will be tried at least once) 1 or 0 occurrences of:
    • .*? - space followed with any 0+ chars other than line break chars, as few as possible
    • 2, - литеральная подстрока
    • ([a-z]) - Группа 1: строчная буква
  • .* - любые символы 0+, кроме символов разрыва строки (остальная часть строки)
  • $ - конец строки.

Общая схема будет выглядеть

^<MANADATORY_LITERAL>(?:<NON_GREEDY_DOT>(<OPTIONAL_PART>))?<GREEDY_DOT>$
person Wiktor Stribiżew    schedule 14.11.2018
comment
И затем вы добавили объяснение. Таким образом, необязательная группа — жадная. В таком случае, почему он не имел приоритет над предыдущей нежадной частью в моей попытке 1? - person Mark Jeronimus; 14.11.2018
comment
@MarkJeronimus Ваш ^Foo: .*?(?:2,([a-z]))?.*?$ не сработал, потому что после того, как Foo: с пробелом сопоставляется, .*? ничего не соответствует (пустой текст), затем (?:2,([a-z]))? ничего не соответствует (пустой текст) - ПРИМЕЧАНИЕ, он будет соответствовать какому-то тексту, если этот шаблон группы немедленно после пробела, как это делается с вашей строкой 1) - а затем последний .*?$ захватывает всю строку. - person Wiktor Stribiżew; 14.11.2018