У меня есть следующее regexp:
/(?:[\[\{]*)(?:([AG\-][^AG\]\}]*)+)(?:[\]\}]*)/
со следующим выражением:
{A''BsCb}
Я ожидаю 3 согласованных результата
A'' Bs Cb
но тестирование на https://regex101.com/ дает мне последнее совпадение Cb
и говорит мне, что группа повторного захвата будет захватывать только последнюю итерацию, помещая группу захвата вокруг повторяющейся группы.
Я думал, это было то, что я сделал! Я думал, что понял проблему, описанную здесь http://www.regular-expressions.info/captureall.html Следовательно, скобки за пределами моего + с группой захвата внутри.
Но либо это слишком поздно, либо мне нужен кто-то, кто головой, не взорвется при упоминании regexp, чтобы показать мне, где я ошибся.
Вы пытаетесь сопоставить повторяющиеся группы захвата и получать снимки. Это невозможно с PHP регулярным выражением PCRE.
Вы можете сделать так, чтобы вы либо извлекли все подстроки {...}
/ [...]
, обрезали их из скобок и использовали простое [AG-][^AG]*
regex, или добавили \G
оператора и сделать ваше регулярное выражение неподъемным, но работающим как оригинальное.
Решение 1
/(?:[[{]*|(?!\A)\G)\K[AG-][^AG\]}]*/
См. Демо-версию regex . Примечание: это регулярное выражение не проверяет закрытие ]
или }
, но его можно добавить с положительным взглядом.
(?:[[{]*|(?!\A)\G)
– соответствует значению [
или {
, ноль или более, или конечное местоположение предыдущего успешного совпадения \K
– опускает текст, сопоставленный до сих пор [AG-]
– буквы от A
до G
и a -
[^AG\]}]*
– ноль или более символов, отличных от A
до G
и кроме ]
и }
. См. Демонстрацию PHP .
Решение 2
$re = '/(?|{([^}]*)}|\[([^]]*)])/'; $str = "{A''BsCb}"; $res = array(); preg_match_all($re, $str, $m); foreach ($m[1] as $match) { preg_match_all('~[AG-][^AG]*~', $match, $tmp); $res = array_merge($tmp, $res); } print_r($res);
См. Демонстрацию PHP
Регулярное выражение (?|{([^}]*)}|\[([^]]*)])
Соответствует строкам типа {...}
или [...]
(но не {...]
или [...}
) и фиксирует содержимое между скобками в группу 1 (поскольку группа сброса ветвей (?|...)
сбрасывает идентификаторы групп в каждой ветке). Тогда все, что нам нужно, это захватить то, что нам нужно, с более последовательным регулярным выражением '~[AG-][^AG]*~'
.
Вы можете получить его с помощью этого шаблона с preg_match_all
в элементе 0:
~ (?: \G (?!\A) # contiguous to previous match, but not at the start of the string | { (?=[^}]* }) # start with { and check if a closing bracket follows | \[ (?=[^]]* ]) # the same for square bracket ) \K # start the match result here [AG] [^]AG}]* ~xS
демонстрация
Вы уже поняли это. Что касается комментария @ sln, нет никакого способа собрать каждое сингулярное совпадение в одной или разных группах захвата, повторяя группу в PCRE, которая является ароматом регулярного выражения PHP. В этом случае фиксируется только последнее совпадение.
Однако, если утверждать, что фигурные скобки должны быть там в начале и конце строки, это не важно, и вам нужны только те значения, которые меньше выполняются:
$array = array_filter(preg_split("~(?=[AG])~", trim("{A''BsCb}", '[{}]')));
Regex:
(?=[AG]) # Positive lookahead to find next character be one from character class
Это регулярное выражение будет соответствовать всем аналогичным позициям для вывода правильных данных по split:
array(3) { [1]=> string(3) "A''" [2]=> string(2) "Bs" [3]=> string(2) "Cb" }
Демо-версия