Negative Lookbehind Equivalent in JavaScript

Negative lookbehind equivalent in JavaScript

Lookbehind Assertions got accepted into the ECMAScript specification in 2018.

Positive lookbehind usage:

console.log(
"$9.99 €8.47".match(/(?<=\$)\d+\.\d*/) // Matches "9.99"
);

Javascript Regex negative lookbehind Alternative

You may use

/^(?!.*\.h\.scss$).*\.scss$/

See the regex demo

Details

  • ^ - start of string anchor
  • (?!.*\.h\.scss$) - a negative lookahead failing the match if the string ends with .h.scss
  • .* - any 0+ chars as many as possible
  • \.scss - a .scss substring at the...
  • $ - end of the string.

Alternative to negative lookbehind?

Let's first consider how it would be done with a lookbehind.
Then we just check if before what we capture is the start of the line, or a whitespace:

(?<=^|\s)(\.\d{5,})

We could simply change that lookbehind to a normal capture group.

Which means a preceding whitespace also gets captured. But in a replace we can just use or not use that capture group 1.

(^|\s)(\.\d{5,})

In the PCRE regex engine we have \K

\K : resets the starting point of the reported match. Any previously
consumed characters are no longer included in the final match

So by using that \K in the regex, the preceding space isn't included in the match

(?:^|\s)\K(\.\d{5,})

A test here

However, if you use Rubi's scan with a regex that has capture groups?

Then it seems that it only outputs the capture groups (...), but not the non-capture groups (?:...) or what's not in a capture group.

For example:

m = '.12345 .123456 NOT.1234567'.scan(/(?:^|\s)(\.\d{5,})/)
=> [[".12345"], [".123456"]]

m = 'ab123cd'.scan(/[a-z]+(\d+)(?:[a-z]+)/)
=> [["123"]]

So when you use scan, lookarounds don't need to be used.

Alternative for negative lookbehind regex not working in Firefox

You may find all matches of new RegExp(`(\\W|^)(${escapedQuery})`, "gi"), check if Group 1 matched, and populate the final chunk array by appending substrings of the original string at appropriate indices only.

See an example:

function splitSpecial(s, query) {

var current=0, res=[], rx = new RegExp("(\\W|^)(" + query.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + ")", "gi");

while (m=rx.exec(s)) {

res.push(s.substring(current, m.index + (m[1] ? 1 : 0)));

res.push(m[2]);

current = m.index + m[0].length;

}

if (current < s.length) {

res.push(s.substr(current));

}

return res;

}

console.log(splitSpecial("@abc abc@abc @abc,@abc!@abc", "@abc"));

// => ["", "@abc", " abc@abc ", "@abc", ",", "@abc", "!", "@abc" ]

Regex lookahead AND lookbehind

You could use a regex replace with an alternation and callback:

var input = "Hello ® and also <sup>®</sup>";
var output = input.replace(/<sup>®<\/sup>|®/g, (x) => x === "<sup>®</sup>" ? x : "<sup>®</sup>");
console.log(output);


Related Topics



Leave a reply



Submit