Comment: Declaration of all regex sub-routines:
Definition Group(?(DEFINE)
# This sub-routine will match an attribute value with or without the quotes around it.
# So it will match "https://example.com" or 'https://example.com' (example with href)
# but also match my-class-name if we had something like <div class=my-class-name>
(?<attr_value_with_delim>(?:(?<delimiter>["']).*?(?:\k<delimiter>)|[^"'=<>\s]+))
) Comment: This sub-routine will match an attribute value with or without the quotes around it.
Comment: So it will match "https://example.com" or 'https://example.com' (example with href)
Comment: but also match my-class-name if we had something like <div class=my-class-name>
Group attr_value_with_delim(?<attr_value_with_delim>(?:(?<delimiter>["']).*?(?:\k<delimiter>)|[^"'=<>\s]+)) Non-Capturing Group(?:(?<delimiter>["']).*?(?:\k<delimiter>)|[^"'=<>\s]+) 1st Alternative(?<delimiter>["']).*?(?:\k<delimiter>) Group delimiter(?<delimiter>["']) "the literal " (3410 / 428 / 2216)
'the literal ' (3910 / 478 / 2716)
.*?any character, repeated any number of times
Non-Capturing Group(?:\k<delimiter>) \k<delimiter>the text saved by group delimiter
2nd Alternative[^"'=<>\s]+ Negated Character Class[^"'=<>\s]+ +matches at least one character outside the set below:
"the literal " (3410 / 428 / 2216)
'the literal ' (3910 / 478 / 2716)
=the literal = (6110 / 758 / 3D16)
<the literal < (6010 / 748 / 3C16)
>the literal > (6210 / 768 / 3E16)
\sany whitespace character
Comment: The regex pattern starts here:
Comment: Match an opening <a> tag.
\s*any whitespace character, repeated any number of times
athe literal a (9710 / 1418 / 6116) (case insensitive)
\s+any whitespace character, repeated at least once
Comment: All the attributes are optional as <a name="my-anchor"></a> is allowed.
Comment: But you can remove the ? at the end if you want to make them mandatory.
Comment: You may also add other attributes such as hreflang, type, data-*, etc.
Positive Lookahead(?=[^>]*\bhref\s*=\s*(?<href>\g<attr_value_with_delim>))? ?repeats the group contents below at most once:
Negated Character Class[^>]* *matches any number of characters outside the set below:
>the literal > (6210 / 768 / 3E16)
\ban ASCII word boundary
hrefthe literal text href (case insensitive) \s*any whitespace character, repeated any number of times
=the literal = (6110 / 758 / 3D16)
\s*any whitespace character, repeated any number of times
Group href(?<href>\g<attr_value_with_delim>) \g<attr_value_with_delim>calls group attr_value_with_delim as a subroutine
Positive Lookahead(?=[^>]*\bid\s*=\s*(?<id>\g<attr_value_with_delim>))? ?repeats the group contents below at most once:
Negated Character Class[^>]* *matches any number of characters outside the set below:
>the literal > (6210 / 768 / 3E16)
\ban ASCII word boundary
idthe literal text id (case insensitive) \s*any whitespace character, repeated any number of times
=the literal = (6110 / 758 / 3D16)
\s*any whitespace character, repeated any number of times
Group id(?<id>\g<attr_value_with_delim>) \g<attr_value_with_delim>calls group attr_value_with_delim as a subroutine
Positive Lookahead(?=[^>]*\bclass\s*=\s*(?<class>\g<attr_value_with_delim>))? ?repeats the group contents below at most once:
Negated Character Class[^>]* *matches any number of characters outside the set below:
>the literal > (6210 / 768 / 3E16)
\ban ASCII word boundary
classthe literal text class (case insensitive) \s*any whitespace character, repeated any number of times
=the literal = (6110 / 758 / 3D16)
\s*any whitespace character, repeated any number of times
Group class(?<class>\g<attr_value_with_delim>) \g<attr_value_with_delim>calls group attr_value_with_delim as a subroutine
Positive Lookahead(?=[^>]*\bname\s*=\s*(?<name>\g<attr_value_with_delim>))? ?repeats the group contents below at most once:
Negated Character Class[^>]* *matches any number of characters outside the set below:
>the literal > (6210 / 768 / 3E16)
\ban ASCII word boundary
namethe literal text name (case insensitive) \s*any whitespace character, repeated any number of times
=the literal = (6110 / 758 / 3D16)
\s*any whitespace character, repeated any number of times
Group name(?<name>\g<attr_value_with_delim>) \g<attr_value_with_delim>calls group attr_value_with_delim as a subroutine
Positive Lookahead(?=[^>]*\btarget\s*=\s*(?<target>\g<attr_value_with_delim>))? ?repeats the group contents below at most once:
Negated Character Class[^>]* *matches any number of characters outside the set below:
>the literal > (6210 / 768 / 3E16)
\ban ASCII word boundary
targetthe literal text target (case insensitive) \s*any whitespace character, repeated any number of times
=the literal = (6110 / 758 / 3D16)
\s*any whitespace character, repeated any number of times
Group target(?<target>\g<attr_value_with_delim>) \g<attr_value_with_delim>calls group attr_value_with_delim as a subroutine
Positive Lookahead(?=[^>]*\btitle\s*=\s*(?<title>\g<attr_value_with_delim>))? ?repeats the group contents below at most once:
Negated Character Class[^>]* \ban ASCII word boundary
titlethe literal text title (case insensitive) \s*any whitespace character, repeated any number of times
=the literal = (6110 / 758 / 3D16)
\s*any whitespace character, repeated any number of times
Group title(?<title>\g<attr_value_with_delim>) Positive Lookahead(?=[^>]*\bdownload\s*=\s*(?<download>\g<attr_value_with_delim>))? Positive Lookahead(?=[^>]*\brel\s*=\s*(?<rel>\g<attr_value_with_delim>))? Negated Character Class[^>]* \s*any whitespace character, repeated any number of times
\/the literal / (4710 / 578 / 2F16)
\s*any whitespace character, repeated any number of times
athe literal a (9710 / 1418 / 6116) (case insensitive)
\s*any whitespace character, repeated any number of times
>the literal > (6210 / 768 / 3E16)
i modifier: insensitive. Matches without distinguishing uppercase and lowercase letters
s modifier: single line. Allows a dot to match line terminators
x modifier: extended. Ignores unescaped whitespace and comments outside character classes
g modifier: global. Finds all matches instead of stopping after the first