Is there a way to achieve the equivalent of a negative lookbehind in javascript regular expressions? I need to match a string that does not start with a specific set of characters.
It seems I am unable to find a regex that does this without failing if the matched part is found at the beginning of the string. Negative lookbehinds seem to be the only answer, but javascript doesn't have one.
EDIT: This is the regex that I would like to work, but it doesn't:
(?<!([abcdefg]))m
So it would match the 'm' in 'jim' or 'm', but not 'jam'
Let's suppose you want to find all
int
not preceded byunsigned
:With support for negative look-behind:
Without support for negative look-behind:
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:
would translate to:
You might need to play with capturing groups to find exact spot of the string that interests you or you want to replace specific part with something else.
Use
Mijoja's strategy works for your specific case but not in general:
Here's an example where the goal is to match a double-l but not if it is preceded by "ba". Note the word "balll" -- true lookbehind should have suppressed the first 2 l's but matched the 2nd pair. But by matching the first 2 l's and then ignoring that match as a false positive, the regexp engine proceeds from the end of that match, and ignores any characters within the false positive.
Lookbehind Assertions got accepted into the ECMAScript specification in 2018. This has been implemented in V8 and shipped without flags with Google Chrome v62 and in Node.js v6 behind a flag and v9 without a flag. So, if you're developing for a Chrome-only environment (such as Electron), or Node, you can start using lookbehinds today!
Positive lookbehind usage:
Negative lookbehind usage:
Support on other platforms:
As Javascript supports negative lookahead, one way to do it is:
reverse the input string
match with a reversed regex
reverse and reformat the matches
Example 1:
Following @andrew-ensley's question:
Outputs:
Example 2:
Following @neaumusic comment (match
max-height
but notline-height
, the token beingheight
):Outputs:
following the idea of Mijoja, and drawing from the problems exposed by JasonS, i had this idea; i checked a bit but am not sure of myself, so a verification by someone more expert than me in js regex would be great :)
my personal output:
the principle is to call
checker
at each point in the string between any two characters, whenever that position is the starting point of:--- any substring of the size of what is not wanted (here
'ba'
, thus..
) (if that size is known; otherwise it must be harder to do perhaps)--- --- or smaller than that if it's the beginning of the string:
^.?
and, following this,
--- what is to be actually sought (here
'll'
).At each call of
checker
, there will be a test to check if the value beforell
is not what we don't want (!== 'ba'
); if that's the case, we call another function, and it will have to be this one (doer
) that will make the changes on str, if the purpose is this one, or more generically, that will get in input the necessary data to manually process the results of the scanning ofstr
.here we change the string so we needed to keep a trace of the difference of length in order to offset the locations given by
replace
, all calculated onstr
, which itself never changes.since primitive strings are immutable, we could have used the variable
str
to store the result of the whole operation, but i thought the example, already complicated by the replacings, would be clearer with another variable (str_done
).i guess that in terms of performances it must be pretty harsh: all those pointless replacements of '' into '',
this str.length-1
times, plus here manual replacement by doer, which means a lot of slicing... probably in this specific above case that could be grouped, by cutting the string only once into pieces around where we want to insert[match]
and.join()
ing it with[match]
itself.the other thing is that i don't know how it would handle more complex cases, that is, complex values for the fake lookbehind... the length being perhaps the most problematic data to get.
and, in
checker
, in case of multiple possibilities of nonwanted values for $behind, we'll have to make a test on it with yet another regex (to be cached (created) outsidechecker
is best, to avoid the same regex object to be created at each call forchecker
) to know whether or not it is what we seek to avoid.hope i've been clear; if not don't hesitate, i'll try better. :)