javascript regex - look behind alternative?

JavascriptRegex

Javascript Problem Overview


Here is a regex that works fine in most regex implementations:

(?<!filename)\.js$

This matches .js for a string which ends with .js except for filename.js

Javascript doesn't have regex lookbehind. Is anyone able put together an alternative regex which achieve the same result and works in javascript?

Here are some thoughts, but needs helper functions. I was hoping to achieve it just with a regex: http://blog.stevenlevithan.com/archives/mimic-lookbehind-javascript

Javascript Solutions


Solution 1 - Javascript

EDIT: From ECMAScript 2018 onwards, lookbehind assertions (even unbounded) are supported natively.

In previous versions, you can do this:

^(?:(?!filename\.js$).)*\.js$

This does explicitly what the lookbehind expression is doing implicitly: check each character of the string if the lookbehind expression plus the regex after it will not match, and only then allow that character to match.

^                 # Start of string
(?:               # Try to match the following:
 (?!              # First assert that we can't match the following:
  filename\.js    # filename.js 
  $               # and end-of-string
 )                # End of negative lookahead
 .                # Match any character
)*                # Repeat as needed
\.js              # Match .js
$                 # End of string

Another edit:

It pains me to say (especially since this answer has been upvoted so much) that there is a far easier way to accomplish this goal. There is no need to check the lookahead at every character:

^(?!.*filename\.js$).*\.js$

works just as well:

^                 # Start of string
(?!               # Assert that we can't match the following:
 .*               # any string, 
  filename\.js    # followed by filename.js
  $               # and end-of-string
)                 # End of negative lookahead
.*                # Match any string
\.js              # Match .js
$                 # End of string

Solution 2 - Javascript

^(?!filename).+\.js works for me

tested against:

  • test.js match
  • blabla.js match
  • filename.js no match

A proper explanation for this regex can be found at Regular expression to match string not containing a word?

Look ahead is available since version 1.5 of javascript and is supported by all major browsers

Updated to match filename2.js and 2filename.js but not filename.js

(^(?!filename\.js$).).+\.js

Solution 3 - Javascript

Let's suppose you want to find all int not preceded by unsigned :

With support for negative look-behind:

(?<!unsigned )int

Without support for negative look-behind:

((?!unsigned ).{9}|^.{0,8})int

Basically idea is to grab n preceding characters and exclude match with negative look-ahead, but also match the cases where there's no preceeding n characters. (where n is length of look-behind).

So the regex in question:

(?<!filename)\.js$

would translate to:

((?!filename).{8}|^.{0,7})\.js$

You might need to play with capturing groups to find exact spot of the string that interests you or you want't to replace specific part with something else.

Solution 4 - Javascript

If you can look ahead but back, you could reverse the string first and then do a lookahead. Some more work will need to be done, of course.

Solution 5 - Javascript

This is an equivalent solution to Tim Pietzcker's answer (see also comments of same answer):

^(?!.*filename\.js$).*\.js$

It means, match *.js except *filename.js.

To get to this solution, you can check which patterns the negative lookbehind excludes, and then exclude exactly these patterns with a negative lookahead.

Solution 6 - Javascript

Below is a positive lookbehind JavaScript alternative showing how to capture the last name of people with 'Michael' as their first name.

  1. Given this text:

    const exampleText = "Michael, how are you? - Cool, how is John Williamns and Michael Jordan? I don't know but Michael Johnson is fine. Michael do you still score points with LeBron James, Michael Green Miller and Michael Wood?";

get an array of last names of people named Michael. The result should be: ["Jordan","Johnson","Green","Wood"]

  1. Solution:

    function getMichaelLastName2(text) { return text .match(/(?:Michael )([A-Z][a-z]+)/g) .map(person => person.slice(person.indexOf(' ')+1)); }

    // or even .map(person => person.slice(8)); // since we know the length of "Michael "

  2. Check solution

    console.log(JSON.stringify( getMichaelLastName(exampleText) )); // ["Jordan","Johnson","Green","Wood"]

Demo here: http://codepen.io/PiotrBerebecki/pen/GjwRoo

You can also try it out by running the snippet below.

const inputText = "Michael, how are you? - Cool, how is John Williamns and Michael Jordan? I don't know but Michael Johnson is fine. Michael do you still score points with LeBron James, Michael Green Miller and Michael Wood?";



function getMichaelLastName(text) {
  return text
    .match(/(?:Michael )([A-Z][a-z]+)/g)
    .map(person => person.slice(8));
}

console.log(JSON.stringify(    getMichaelLastName(inputText)    ));

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiondanielView Question on Stackoverflow
Solution 1 - JavascriptTim PietzckerView Answer on Stackoverflow
Solution 2 - JavascriptBenjamin Udink ten CateView Answer on Stackoverflow
Solution 3 - JavascriptKamil SzotView Answer on Stackoverflow
Solution 4 - JavascriptAlbert FriendView Answer on Stackoverflow
Solution 5 - JavascriptweibeldView Answer on Stackoverflow
Solution 6 - JavascriptPiotr BerebeckiView Answer on Stackoverflow