PHP regex для обнаружения текста внутри скобок, игнорируя вложенные скобки
Я пытаюсь сделать PHP regex, который анализирует строку для текста в скобках, игнорируя возможные вложенные скобки:
допустим, я хочу!--4-->
Lorem ipsum [1. dolor sit amet, [consectetuer adipiscing] elit.]. Aenean commodo ligula eget dolor.[2. Dolor, [consectetuer adipiscing] elit.] Aenean massa[3. Lorem ipsum] dolor.
вернуться
[1] => "dolor sit amet, [consectetuer adipiscing] elit."
[2] => "Dolor, [consectetuer adipiscing] elit."
[3] => "Lorem ipsum"
до сих пор я получил
'/[([0-9]+).s([^]]+)]/gi'
но он ломается, когда возникают вложенные скобки. посмотреть демо
как я могу игнорировать внутренние скобки от обнаружения? Заранее спасибо!
3 ответов
вы можете использовать этот шаблон, который фиксирует номер лота и следующий текст в двух разных группах. Если вы уверены, что все номера элементов уникальны, вы можете построить ассоциативный массив, описанный в вашем вопросе, с помощью простого array_combine
:
$pattern = '~\[ (?:(\d+)\.\s)? ( [^][]*+ (?:(?R) [^][]*)*+ ) ]~x';
if (preg_match_all($pattern, $text, $matches))
$result = array_combine($matches[1], $matches[2]);
узор детали:
~ # pattern delimiter
\[ # literal opening square bracket
(?:(\d+)\.\s)? # optional item number (*)
( # capture group 2
[^][]*+ # all that is not a square bracket (possessive quantifier)
(?: #
(?R) # recursion: (?R) is an alias for the whole pattern
[^][]* # all that is not a square bracket
)*+ # repeat zero or more times (possessive quantifier)
)
] # literal closing square bracket
~x # free spacing mode
(*) обратите внимание, что часть номера элемента должна быть необязательной, если вы хотите использовать рекурсию с (?R)
(например,[consectetuer adipiscing]
нет пункта число.). Это может быть проблематично, если вы хотите избежать квадратных скобок без номера товара. В этом случае вы можете создать более надежный шаблон, если измените необязательную группу (?:(\d+)\.\s)?
к условному заявлению:(?(R)|(\d+)\.\s)
условный оператор:
(?(R) # IF you are in a recursion
# THEN match this (nothing in our case)
| # ELSE
(\d+)\.\s #
)
таким образом, номер товара становится обязательным.
Вы можете использовать рекурсивные ссылки на предыдущие группы:
(?<no_brackets>[^\[\]]*){0}(?<balanced_brackets>\[\g<no_brackets>\]|\[(?:\g<no_brackets>\g<balanced_brackets>\g<no_brackets>)*\])
идея состоит в том, чтобы определить желаемые матчи как что-то без скобок, окруженное []
или что-то, что содержит последовательность без скобки или скобки с первым правилом.
вы можете использовать рекурсивное регулярное выражение для получения всех подстрок, заключенных в квадратные скобки, а затем использовать preg_replace
внутри array_map
чтобы снять скобки и заключительные скобки:
$str = "Lorem ipsum [1. dolor sit amet, [consectetuer adipiscing] elit.]. Aenean commodo ligula eget dolor.[2. Dolor, [consectetuer adipiscing] elit.] Aenean massa[3. Lorem ipsum] dolor.";
preg_match_all('/\[(?>[^\[\]]|(?R))*]/', $str, $matches);
$res = array_map(function($el) {
return preg_replace('/^\[\d+\.(.*?)\s*\]$/s', '', $el);
},
$matches[0]);
print_r($res);
посмотреть IDEONE demo
на \[(?>[^\[\]]|(?R))*]
regex матчи [
, тогда что угодно, кроме [
и ]
или вложенный элемент [...]
конструктов. См. больше о рекурсии с regex at regular-expressions.info. Вот это регулярное выражение демо.
регулярное выражение внутри preg_repace
- ^\[\d+\.(.*?)\s*\]$
- будет соответствовать инициалу [
С 1 или более цифр и период после, и матч и захватить остальные до окончательного необязательного пробела (\s*
) и закрывающим тегом ]
(the $
убедитесь, что скобка соответствует в конце строки). С мы можем восстановить остальную часть строки и использовать ее для заполнения нового массива. Вижу 2-я демонстрация regex здесь.