Here is a regex that works fine in most regex implementations:
(?
This matches .js for a string which ends with .js exc
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.
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.
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"]
2) 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 "
3) 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) ));
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
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.
^(?!filename).+\.js
works for me
tested against:
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