Instead of writing a long uncommented regex, compose it out of multiple parts. This makes it easier to understand what you're trying to do.
Let's go through the spec for a start tag:
- The first character of a start tag must be a "<" (U+003C) character.
- The next few characters of a start tag must be the element's tag name.
- If there are to be any attributes in the next step, there must first be one or more space characters.
- Then, the start tag may have a number of attributes, the syntax for which is described below. Attributes must be separated from each other by one or more space characters.
- After the attributes, or after the tag name if there are no attributes, there may be one or more space characters. (Some attributes are required to be followed by a space. See the attributes section below.)
- Then, if the element is one of the void elements, or if the element is a foreign element, then there may be a single "/" (U+002F) character. This character has no effect on void elements, but on foreign elements it marks the start tag as self-closing.
- Finally, start tags must be closed by a ">" (U+003E) character.
Expressed as a regex fragment, with insignificant whitespace:
$start_tag = "(?: [<] script (?: $ws+ (?:$attribute $ws+)* $attribute)? $ws* [>] )"
Attributes themselves are rather complex. They can either be empty, unquoted, single-quoted or double-quoted.
$attribute = "(?: $attr_name
| $attr_name $ws* [=] $ws* (?:[^${space_characters}\"'<>`&]+|$character_reference)+
| $attr_name $ws* [=] $ws* [\"] (?:[^\"&]|$character_reference)* [\"]
| $attr_name $ws* [=] $ws* ['] (?:[^'&]|$character_reference)* [']
)"
Now once we fill in the appropriate values for character references and the space character recognized by HTML5 and possible attribute names, we have finally correctly matched the <script>
start tag.
How does your solution hold up? I am led to believe that this part is supposed to match the start tag (I added whitespace for clarity):
<script (?: [^>"]* (?:"[^"]*")? )* >
Err, no. This fails to match single-quoted strings <script title='<You Fail>'>
. This will also match some strings that do not contain valid HTML at all, like <script <<<<<<<>
.
What is the point of this exercise? It's absolutely possible to correctly match HTML with the PCRE (it's not possible with a regular language, which has a specific computer science meaning. Too many people confuse the theoretical concept with a similarly named practical tool which happens to be more powerful). However, if you do want to do this, you have to follow the spec. Don't fudge it, read it. (Actually, I fudged it as well, but to a lesser degree. Do as I say, not as I do).
It is absolutely possible to write readable regexes. Compose them from multiple reusable parts. Use the /x
option to include insignificant whitespace. But do not ram them onto a single line. That's just obfuscation, and you wouldn't do that in other languages.