Я экспериментировал с регулярным выражением и застрял в следующей проблеме.
Скажем, у меня есть строки, которые начинаются и заканчиваются демартером и некоторым количеством арбита между ними, и мне нужны числа в группе захвата, а также слова batman
.
batman 12345 batman batman 234 batman batman 35655 batman batman 1311 batman
Это легко достичь (просто один => (\s*batman (\d+) batman\s*)
DEMO ).
Теперь я попробовал немного больше. capture tag (#capture)
те же данные в capture tag (#capture)
#capture batman 12345 batman batman 234 batman batman 35655 batman batman 1311 batman #capture #others batman 12345 batman batman 234 batman batman 35655 batman batman 1311 batman #others
Я пытаюсь захватить строки только между #capture
и я попытался
(?:#capture)(\s*batman (\d+) batman\s*)*(?:#capture)
который соответствует шаблону, но включает только последнюю итерацию в группе захвата, то есть $1=>batman $2=>1311 $1=>batman
DEMO
Я также попытался захватить повторяющуюся группу, используя
(?:#capture)((\s*batman (\d+) batman\s*)*)(?:#capture)
Это захватывает все .. но в разных группах .. DEMO
Может ли кто-нибудь помочь мне понять и решить эту проблему?
Ожидаемые результаты: захватить только группу в #capture
и все номера в группе, чтобы замена могла быть легкой.
Благодарю.
Вы можете использовать нефиксированный вид ширины в стиле .NET regex и использовать это регулярное выражение:
(?s)(?<=#capture.*?)(?:batman (\d+) batman)(?=.*?#capture)
Однако этот пример работает для случая, который вы предоставили (например, он не будет работать, если в тексте больше блоков #capture...#capture
), и вам просто нужно будет добавить больше ограничений на основе контекста тега.
В PCRE / Perl вы можете добиться аналогичного результата с объявлением того, что мы хотим пропустить:
(?(DEFINE) # Definitions (?<skip>\#others.*?\#others) # What we should skip ) (?&skip)(*SKIP)(*FAIL) # Skip it | (?<needle>batman\s+(\d+)\s+batman) # Match it
И, скажем, замените batman new-$3 batman
.
См. Эту демонстрацию в regex101 .
Поскольку PCRE не может хранить повторные захваты, как с .net-каркасом или новым модулем регулярных выражений Python, возможно использование функции \G
и проверка после того, как вы убедитесь, что достигнут конец блока.
Якорь \G
отмечает позицию в конце предыдущего совпадения и используется в глобальном исследовательском контексте (с preg_match_all
или preg_replace*
). Полезно найти смежные результаты. Обратите внимание, что до первого совпадения \G
по умолчанию по умолчанию начинается строка. Чтобы предотвратить \G
чтобы преуспеть в начале строки, вам нужно добавить отрицательный lookahead (?!\A)
.
$pattern = '~ (?: # two possible branches \G(?!\A) # the contiguous branch | [#]capture \R # the start branch: only used for the first match ) (batman \h+ ([0-9]+) \h+ batman) \R # alias for any kind of newlines (?: ([#]) (?=capture) )? # the capture group 3 is used as a flag # to know if the end has been reached. # Note that # is not in the lookahead to # avoid the start branch to succeed ~x'; if (preg_match_all($pattern, $text, $matches) && array_pop($matches[3])) { print_r($matches[1]); }