$re = '/^
(?P<group>
(?P<structured>
(?P<single>
(?P<tag_first>
(?P<tag>
\d+(?:\/\d+)+
|
(?P<repnum>\$+(?:@\^*-?\d*)?)
|
[\w:!-]
)++
(?P<attr>
(?P<short_attr>
\.
(?P<short_val>
(?P>repnum)
|
[\w:!-]
)*
|
\#(?P>short_val)*
)
|
(?P<long_attr>
\[
(?P<attr_pair>
(?P<attr_name>
\\\\(?:\\\\{2})*["\'\s]
|
[^\[\]"\'\s\\\\]
)+
\.?
(?P<equal_val>
=
(?P<attr_val>
(?P<unquoted_val>
\\\\(?:\\\\{2})*[\[\]"\'\s]
|
[^\[\]"\'\s\\\\]
)+
|
(?P<quoted_val>
(?P<quote>["\'])
(?:
(?P<escaped_all>\\\\(?:\\\\{2})*.)
|
[^"\'\n\\\\]
)*
(?P=quote)
)
)?
)?
)?
(?:\s+(?P>attr_pair))*
\]
)
)*
|
(?P>attr)+
)
(?P<tag_rest>
(?P<text>
\{
(?P<text_content>
(?P>escaped_all)
|
[^{}\n\\\\]
)*
\}
)
(?P>attr)*
(?:
(?P<rep>\*\d*+)?
(?P>attr)*
(?P<close>\/)?
|
(?P>close)?
(?P>rep)?
)
|
(?P>rep)
(?P>attr)*
(?P>text)?
(?P>attr)*
(?P>close)?
|
(?P>close)
(?P>rep)?
)?
|
(?P<text_first>(?P>text)(?P>attr)*)
(?P<text_rest>
(?P>rep)
(?P>attr)*
(?P>close)?
|
(?P>close)
(?P>rep)?
)?
)
(?:
(?P<relation>[>+]|\^+)
(?P>group)*
)?
)
|
\(
(?P>group)*
\)
(?P>rep)?
(?P>relation)?
)+
$/mx';
$str = '>>> tag <<<
tag
$
tag$with$@^^^-2repnum
1
1/2
1/2/3
tag1/2with1/2/3fraction
tag$@with1/2both
ri:a
!
!!!
-
:
===XXX===
@
&
>>> short attr <<<
#
###
#id
#id1#id2
#id$@^^^-2
.
.#
...
.class
.class1.class2
.class#id.class
.class$@^-2type
.class-data
.!class
.class:subclass
===XXX===
.@
.汉字
>>> long attr <<<
[]
[key]
[key.]
[key...]
[key=]
[key.=]
[key=val]
[key.=val]
[key=\'val\']
[key=\'val with space\']
[key=\'val\\\\\\\'ue\']
[key1=val1 key2=val2]
[][]
[key][key]
.class[key]
[key].class
[汉字=汉字]
===XXX===
[\\[]
[key=\'val\\\\\'ue\']
>>> text <<<
{}
{text}
{text with space}
{text with escaped \\{ and \\}}
{汉字}
tag{text}
.attr{text}
{text}.attr
===XXX===
{\\\\{}
{{}}
>>> repeater <<<
tag*2
.attr*2
{text}*2
.attr{text}*2
.attr{text}.attr*2
===XXX===
*2
tag*2*2
>>> self-close <<<
tag/
.attr/
{text}/
tag*2/
tag/*2
.attr{text}.attr/
.attr*2.attr{text}.attr/
.attr{text}.attr*2.attr/
.attr{text}/*2
tag*2{text}/
===XXX===
/*2
tag//
>>> child <<<
tag>tag
tag.class*2>tag[key]/
tag>
===XXX===
>tag
tag>>
>>> sibling <<<
tag+tag
.class/>[key]+.attr/*2
tag[key]tag
tag{text}tag
tag*2tag
tag/tag
===XXX===
+tag
tag++
>>> parent <<<
tag^tag
tag^^^
tag>tag+tag^tag
===XXX===
^tag
>>> group <<<
()
(())
(tag)
(tag)(tag)
((tag)(tag))
tag>(tag.class)
tag>(tag>tag+tag)
(tag>(tag+tag)*2)*2
(tag)tag
(tag>).class
(tag)*2^tag
(tag*2)^tag
(tag>)^tag
(tag)^
===XXX===
(
(()';
preg_match_all($re, $str, $matches, PREG_SET_ORDER, 0);
// Print the entire match result
var_dump($matches);
Please keep in mind that these code samples are automatically generated and are not guaranteed to work. If you find any syntax errors, feel free to submit a bug report. For a full regex reference for PHP, please visit: http://php.net/manual/en/ref.pcre.php