HTML Tag regex
Matches paired HTML tags with content.
/<([a-z][a-z0-9]*)\b[^>]*>.*?</\1>/giWhat it matches
An opening tag, its attributes, the content, and a matching closing tag. The backreference \1 is the point: it captures the tag name and requires the same name to close, so <div>…</div> matches but <div>…</span> does not. The lazy .*? stops at the first valid close rather than the last.
Railroad diagram
Read left to right. Every path through the diagram is a string the pattern accepts.
Drag to pan. Ctrl+scroll to zoom.
Breakdown
gFind all matches instead of stopping after the firstiLetters match both upper and lower case<Literal "<"[a-z]Match one of: Literal "a"–Literal "z"[a-z0-9]*Match one of: Literal "a"–Literal "z", Literal "0"–Literal "9", zero or more\bWord boundary[^>]*Match not one of: Literal ">", zero or more>Literal ">".*?Any character, zero or more (lazy)<Literal "<"\/Literal "/"\1Backreference to group #1>Literal ">"Test cases
Matches
<div class="test">Hello</div><p>World</p><span id="x">y</span>
Does not match
<br /><div>unclosedplain text
Caveats
Fine for a quick scan, wrong for parsing. Nesting defeats it: the lazy quantifier closes <div><div>a</div></div> at the inner tag. It cannot see comments or CDATA, and content spanning a newline needs the s flag. HTML is not a regular language; for anything real, use a parser.
More web patterns
Test this against your own input in the regex tester, browse the full pattern library, or check the syntax cheat sheet.