Some people, when confronted with a problem, think “I know, I’ll use regular expressions.” Now they have two problems.
Regular Expression Lookbehinds
In particular, I was trying to find a certain substring from a string that did not contain a substring preceding it.
Let’s say I have the strings
'bbccdd'. I might want to be able to locate the substring
'cc' only if it occured at some point after the substring
'aa'. This is called a positive lookbehind, and this would only match the
'cc' in the first string.
On the other hand, if I wanted to match
'cc' only if it does not come after
'aa', this would be a negative lookbehind. This would only match the
'cc' in the second string.
If you’re using Chrome 62 or higher, Node 6.0.0 or higher (with the
--harmony flag), or Node 8.1.10 or higher (see below for finding these details), you can use negative lookbehinds through Google’s V8 engine. Here’s how you would do those cases above:
~: $ nvm use 8.10.0 Now using node v8.10.0 (npm v5.6.0) ~: $ node // Positive lookbehind checking 'aabbcc' for 'cc' preceded by 'aa' at some point > /(?<=aa.*)cc/.exec('aabbcc') [ 'cc', index: 4, input: 'aabbcc' ] // Positive lookbehind checking 'bbccdd' for 'cc' preceded by 'aa' at some point > /(?<=aa.*)cc/.exec('bbccdd') null // Negative lookbehind checking 'aabbcc' for 'cc' not preceded by 'aa' at some point > /(?<!aa.*)cc/.exec('aabbcc') null // Negative lookbehind checking 'bbccdd' for 'cc' not preceded by 'aa' at some point > /(?<!aa.*)cc/.exec('bbccdd') [ 'cc', index: 2, input: 'bbccdd' ]
Looking into compability
In my case, I was trying to do a negative lookbehind for my replacement. I was also attempting to do so with just a regular expression and no additional parsing through a function, as I was passing it to another module. After a few attempts by hand, I did some searching to see if it was possible. The results were not encouraging, mostly indicating in older posts that it was not supported but there were many hacks to work around it.
I then came across 2ality’s blog post on negative lookbehinds, which looked much more promising.
The proposal “RegExp Lookbehind Assertions” by Gorkem Yakin, Nozomu Katō, Daniel Ehrenberg is at stage 4. This blog post explains it.
At this point, I tried the posted examples in both my local Node (version 6.11.1) and Chrome (66). They threw an error in Node, but worked in Chrome. My usecase was part of a Node build script, so although the version was throwing an error, it seemed there was hope for a later version. At this point, I could have just used the most recent version of Node or used the
--harmony flag, but I wanted to confirm versions to ensure that I was able to be exact about the required version for future use.
I then found a more recent blog post by the V8 team from July 2017 featuring upcoming features. In particular:
Then, an even more recent V8 release post from September 2017 for V8 6.2:
More regular expressions features
Lookbehind assertions, another new regular expression feature, are now available by default.
This meant that V8 6.2 had them available, which is why it worked in my Chrome 66. The next check was to the Node releases page. Here’s the relevant section:
This means that V8 version 6.2 made it into Node on March 6, 2018 in version 8.10.0, and V8 version 4.9 (allowing this with the
--harmony flag) made it into Node 6.0.0. After switching to 8.10.0, my negative lookbehinds successfully ran on Node, and I was able to finish the build script.