Группа повторного захвата PCRE

Не могу понять, почему это регулярное выражение (regex101)

/[\|]?([a-z0-9A-Z]+)(?:[\(]?[,][\)]?)?[\|]?/g

захватывает весь ввод, а это (regex101)

/[\|]+([a-z0-9A-Z]+)(?:[\(]?[,][\)]?)?[\|]?/g

захватывает только |Func

Строка ввода - |Func(param1, param2, param32, param54, param293, par13am, param)|

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

/\(\(\s*([a-z\_]+){1}(?:\s+\,\s+(\d+)*)*\s*\)\)/gui

И входная строка - (( string , 1 , 2 )).

Regex101 говорит: «Повторяющаяся группа захвата захватит только последнюю итерацию. Поместите группу захвата вокруг повторяющейся группы, чтобы захватить все итерации ...». Я пытался последовать этому совету, но мне это не помогло.


person user2890234    schedule 11.01.2017    source источник
comment
См. \|+([a-z0-9A-Z]+)(?:\(?(\w+(?:\s*,\s*\w+)*)\)?)?\|?. Вы не можете захватить все повторяющиеся захваты с помощью PCRE, вы можете сопоставить их с помощью регулярного выражения на основе \G. См. (?:\G(?!\A)\s*,\s*|\|+([a-z0-9A-Z]+)\()\K\w+.   -  person Wiktor Stribiżew    schedule 11.01.2017
comment
Не знал, что я не могу захватить все это за один звонок с помощью PCRE. Теперь я понимаю, почему regex101 просил меня захватить повторяющуюся группу, чтобы она соответствовала одному матчу. Спасибо большое за вашу помощь!   -  person user2890234    schedule 11.01.2017


Ответы (1)


Регулярное выражение /[\|]+([a-z0-9A-Z]+)(?:[\(]?[,][\)]?)?[\|]?/g не совпадает, потому что вы не определили шаблон для сопоставления слов в круглых скобках. Вы можете исправить это как \|+([a-z0-9A-Z]+)(?:\(?(\w+(?:\s*,\s*\w+)*)\)?)?\|?, но все значения в круглых скобках будут объединены в одну группу что вам придется разделиться позже.

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

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

Итак, чтобы соответствовать второй строке, вы можете использовать

(?:\G(?!\A)\s*,\s*|\|+([a-z0-9A-Z]+)\()\K\w+

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

Подробности:

  • (?:\G(?!\A)\s*,\s*|\|+([a-z0-9A-Z]+)\() - либо конец предыдущего совпадения (\G(?!\A)) и запятая, заключенная с 0+ пробелами (\s*,\s*), либо 1+ | символов (\|+), за которыми следует 1+ буквенно-цифровых символов (захваченных в Группу 1, ([a-z0-9A-Z]+)) и ( символ (\()
  • \K - пропустить уже найденный текст
  • \w+ - более 1 символа слова.
person Wiktor Stribiżew    schedule 11.01.2017
comment
Я попытался передать второе регулярное выражение в качестве параметра preg_match_all , и это именно то, что мне нужно. Также сопоставление первого регулярного выражения и анализа родительского захвата кажется более ясным, но для этого требуется как минимум +1 preg_match, поэтому я бы выбрал второй вариант. Спасибо за отличное объяснение! - person user2890234; 11.01.2017
comment
Да, только что проголосовал за ваш ответ, когда получил требуемый рейтинг для этого действия :) Пару часов назад мне не хватило рейтинга, чтобы проголосовать - person user2890234; 11.01.2017