Here’s a short guide to lookahead and lookbehind assertions, and how to match text between two markers.
Match between “markers”
I needed a regex that matches everything between a start marker and an end marker. In this example, the highlighted lines should match:
import React from 'react'
// start-match
function Foo() {
return 'Everything between here should be matched'
}
// end-match
export default FooThis helper uses lookbehind and lookahead assertions:
function matchRange(string = '') {
return (
string.match(
/(?<=\/\/ ?start-match\r?\n).*?(?=\r?\n\/\/ ?end-match)/s
)?.[0] ?? null
)
}It returns the text between the first pair of markers, or null if no match is
found.
Detailed explanation
Lookbehind and lookahead check the text around a match without including it. That is exactly what we want here.
Lookbehind ─┐ ┌─ Text, lazily ┌─ Lookahead
│ │ │
┌─────────────┴───────────┐┌┴┐┌───────────────┴──────┐
/(?<=\/\/ ?start-match\r?\n).*?(?=\r?\n\/\/ ?end-match)/sThe assertions sit on either side of .*?, the part that produces the match:
(?<=\/\/ ?start-match\r?\n)checks that the match follows the start marker.*?matches as little text as possible; thesflag lets.match newlines(?=\r?\n\/\/ ?end-match)checks that the match precedes the end marker\r?\nsupports both Windows and Unix line endings
The ? after * matters. Without it, .* is greedy and can run to the last
end marker in the string instead of the first.
Conclusions
JavaScript also supports negative lookahead and negative lookbehind. See MDN’s assertion guide for details. If you’re new to regex, read my beginner-friendly article on the topic.