In this post we will discuss:
- What are Lookbehind Regex
- Browser Compatibility of Lookbehind Regex
- Alternative ways to use them so that it works in all browsers
What are Lookbehind regex
At times, we need to match a pattern only if it is followed or preceded by another pattern.
For eg. in case of URL which contains the organization information:
:org is dynamic name of the organization which can be of following pattern:
We want to match all URLs which match the pattern for
But there are also URLs such as which we don't want to match.
slug is also of same pattern as
So we want to make sure that we match the organizations URLs only if they are preceded by
There is a way to write such regular expressions using Lookbehind regex which checks if a pattern is preceded by specific pattern.
The syntax is:
- Positive lookbehind:
X, but only if there’s
- Negative lookbehind:
X, but only if there’s no
In our case:
const RE = /(?<=organizations\/[a-z0-9]+\/).+$/;
We use this as follows:
trimmedPath = path.replace(RE, '')
Which will basically replace anything that followed our pattern
const RE = /(?<=organizations\/[a-z0-9]+\/).+$/; path = "/organizations/last9/345345435" path.replace(RE, '') // => '/organizations/last9/'
Lookbehind regex are very powerful but they are not supported in all browsers. Non V8 browsers such as Safari don't support them.
Let's run the same example in Safari:
const RE = /(?<=organizations\/[a-z0-9]+\/).+$/; SyntaxError: Invalid regular expression: invalid group specifier name
Alternative to use Lookbehind Regex in Safari
We can relook at our usage and try to avoid the lookbehind regex and just use the capture groups.
const RE = /(organizations\/[a-z0-9]+\/)(.+)$/; path = "/organizations/last9/345345435" path.match(RE) // Two matches => [organizations/last9/, 345345435]
In this case, we capture two groups, the first one where
organizations/:org/ gets captured and then in second everything else.
We want to keep
organizations/:org/ and drop everything else. This can be achieved with following:
const RE = /(organizations\/[a-z0-9]+\/)(.+)$/; path = "/organizations/last9/345345435" path.replace(RE, "$1") // => /organizations/last9/
This basically keeps the first match and drops everything else. Most importantly, this works on Safari as well!