Match text between two markers with regex

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 Foo

This 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)/s

The 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; the s flag lets . match newlines
  • (?=\r?\n\/\/ ?end-match) checks that the match precedes the end marker
  • \r?\n supports 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.