const regex = /^
(?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)?
)+
$/gm;
// Alternative syntax using RegExp constructor
// const regex = new RegExp('^
(?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)?
)+
$', 'gm')
const 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===
(
(()`;
// Reset `lastIndex` if this regex is defined globally
// regex.lastIndex = 0;
let m;
while ((m = regex.exec(str)) !== null) {
// This is necessary to avoid infinite loops with zero-width matches
if (m.index === regex.lastIndex) {
regex.lastIndex++;
}
// The result can be accessed through the `m`-variable.
m.forEach((match, groupIndex) => {
console.log(`Found match, group ${groupIndex}: ${match}`);
});
}
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 JavaScript, please visit: https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions