Regex tester · Guide
Regex Match Between Two Strings: Extracting What Is Inside
Extracting the text between two markers is the most common capture task there is. Three approaches solve it with different trade-offs, and the popular one is usually the worst.
The three approaches
START(.*?)END # lazy — shortest match, needs dotall for newlines
START([^E]*)END # negated class — cannot cross the delimiter
(?<=START).*?(?=END) # lookarounds — match excludes the markersThe lazy version is the most readable and the most portable. The negated class is fastest and only practical when the delimiter is a single character. Lookarounds keep the markers out of the match, which avoids needing a capture group at all.
Greedy versus lazy
This is the trap. START(.*)END on START a END START b END captures a END START b, because the greedy .* runs to the last END and backs off. START(.*?)END captures a, then b on the next match.
Whenever an extraction returns far more than expected, a greedy quantifier is almost always the reason.
Crossing newlines
The dot does not match newlines by default, so START(.*?)END fails when the content spans lines. Enable dotall (/s, re.DOTALL, RegexOptions.Singleline) or use [\s\S]*?, which works in every engine with no flag.
For quoted strings specifically, prefer the negated class: "([^"]*)" cannot run past the closing quote at all, which makes greediness irrelevant and the intent obvious.
When to stop
For a single delimiter pair in flat text, regex is the right tool. For nested markers — balanced parentheses, HTML tags, quoted strings with escapes — it is not: regular expressions cannot count nesting, and patterns that appear to work fail on the first nested case.
.NET balancing groups are the exception and are unreadable. For HTML use a parser; for JSON use a JSON parser; for anything recursive, write the loop.
Frequently asked questions
Why does my capture include everything up to the last delimiter?
The quantifier is greedy. Use .*? or a negated character class.
How do I match across multiple lines?
Enable dotall, or use [\s\S]*? which needs no flag.
Can regex handle nested delimiters?
Not in general. Regular expressions cannot count nesting; use a parser.
Ready to try it?
Open the free browser-based Regex tester and apply what you just read — no sign-up, runs locally.
Open the Regex tester tool