# 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:

```js {4-6}
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:

```ts
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](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Assertions#other_assertions)
for details. If you’re new to regex, read my
[beginner-friendly article on the topic](/easily-digestible-introduction-to-regex-in-javascript).
