[quote]something [quote]something else[/quote] some text here[/quote]
$matches[6][0]: [quote]something [quote]something else[/quote]
$matches[6][0]: [quote]something [quote]something else[/quote] some text here[/quote]
$matches[6][1]: [quote]something else[/quote]
To match a nested structure, you need a recursive pattern, example:
$data = '[quote]something [quote]something else[/quote] some text here[/quote]';
$pattern = '~\[quote](?>[^][]+|(?R))*\[/quote]~';
if (preg_match_all($pattern, $data, $m))
print_r(m);
pattern details:
~ # pattern delimiter: do not choose the slash here
\[quote] #
(?> # open an atomic group: possible content between tags
[^][]+ # all that is not a square bracket
| # OR
(?R) # recurse the whole pattern
)* # close the atomic group, repeat zero or more times
\[/quote] #
~
Note that it's quite easy. But now if your code may contain other parasite tags between "quote" tags, you only need to change the atomic group to allow them (written in extended mode):
(?> [^][]+ | \[/? (?!quote\b) [^]]* ] | (?R) )*
If you feel very ambitious you could sit in a while search loop and build up a nested array of content. Each new core matched needs to causes a reentrant call into the parse function that executes this regex.
# //////////////////////////////////////////////////////
# // The General Guide to 3-Part Recursive Parsing
# // ----------------------------------------------
# // Part 1. CONTENT
# // Part 2. CORE
# // Part 3. ERRORS
(?is)
(?:
( # (1), Take off CONTENT
(?&content)
)
| # OR
\[quote\] # Start-Delimiter
( # (2), Take off The CORE
(?&core)
|
)
\[/quote\] # End-Delimiter
| # OR
( # (3), Take off Unbalanced (delimeter) ERRORS
\[/?quote\]
)
)
# ///////////////////////
# // Subroutines
# // ---------------
(?(DEFINE)
# core
(?<core>
(?>
(?&content)
|
\[quote\]
# recurse core
(?:
(?= . )
(?&core)
|
)
\[/quote\]
)+
)
# content
(?<content>
(?>
(?!
\[/?quote\]
)
.
)+
)
)
You would have to build a tree structure. Check out STML Parser on the CodeProject. STML Parser