Javascript: negative lookbehind equivalent?Javascript Regex; find 'x', but not if preceded by 'y'JavaScript Regex not after a specified characterRegex: Match a phrase if NOT preceded by wordJavascript regex to match string not preceded byRegexp: only match word if it doesn't start with a dotRegex negative lookbehind replace in JavaScriptFiltering existing keywords using regular expressionnegative lookbehind regex javascriptConverting a Regex Expression that works in Chrome to work in FirefoxNegative Look Behind alternative JAVASCRIPTHow to validate an email address in JavaScriptHow do JavaScript closures work?How do I remove a property from a JavaScript object?Which equals operator (== vs ===) should be used in JavaScript comparisons?How do I include a JavaScript file in another JavaScript file?How to replace all occurrences of a string?What does “use strict” do in JavaScript, and what is the reasoning behind it?How to check whether a string contains a substring in JavaScript?How do I remove a particular element from an array in JavaScript?Check whether a string matches a regex in JS
Dropdowns & Chevrons for Right to Left languages
Does the United States guarantee any unique freedoms?
Converting Piecewise function to C code
Why does Intel's Haswell chip allow multiplication to be twice as fast as addition?
How would I as a DM create a smart phone-like spell/device my players could use?
What is my malfunctioning AI harvesting from humans?
(11 of 11: Meta) What is Pyramid Cult's All-Time Favorite?
Was this a rapid SCHEDULED disassembly? How was it done?
Write an interpreter for *
Pretty heat maps
Team goes to lunch frequently, I do intermittent fasting but still want to socialize
Are there any financial disadvantages to living significantly "below your means"?
First amendment and employment: Can an employer terminate you for speech?
Is refreshing multiple times a test case for web applications?
Word or idiom defining something barely functional
Look mom! I made my own (Base 10) numeral system!
Improve survivability of bicycle container
Non-OR journals which regularly publish OR research
Colors and corresponding numbers
Does a code snippet compile? Or does it get compiled?
Want to draw this commutative diagram
Are there any differences in causality between linear and logistic regression?
Why is there a need to prevent a racist, sexist, or otherwise bigoted vendor from discriminating who they sell to?
Ex-contractor published company source code and secrets online
Javascript: negative lookbehind equivalent?
Javascript Regex; find 'x', but not if preceded by 'y'JavaScript Regex not after a specified characterRegex: Match a phrase if NOT preceded by wordJavascript regex to match string not preceded byRegexp: only match word if it doesn't start with a dotRegex negative lookbehind replace in JavaScriptFiltering existing keywords using regular expressionnegative lookbehind regex javascriptConverting a Regex Expression that works in Chrome to work in FirefoxNegative Look Behind alternative JAVASCRIPTHow to validate an email address in JavaScriptHow do JavaScript closures work?How do I remove a property from a JavaScript object?Which equals operator (== vs ===) should be used in JavaScript comparisons?How do I include a JavaScript file in another JavaScript file?How to replace all occurrences of a string?What does “use strict” do in JavaScript, and what is the reasoning behind it?How to check whether a string contains a substring in JavaScript?How do I remove a particular element from an array in JavaScript?Check whether a string matches a regex in JS
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
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'
javascript regex negative-lookbehind
add a comment |
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'
javascript regex negative-lookbehind
Consider posting the regex as it would look with a negative lookbehind; that may make it easier to respond.
– Daniel LeCheminant
Mar 13 '09 at 3:53
add a comment |
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'
javascript regex negative-lookbehind
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'
javascript regex negative-lookbehind
javascript regex negative-lookbehind
edited Apr 17 '09 at 14:49
Andrew Ensley
asked Mar 13 '09 at 3:50
Andrew EnsleyAndrew Ensley
7,37515 gold badges53 silver badges72 bronze badges
7,37515 gold badges53 silver badges72 bronze badges
Consider posting the regex as it would look with a negative lookbehind; that may make it easier to respond.
– Daniel LeCheminant
Mar 13 '09 at 3:53
add a comment |
Consider posting the regex as it would look with a negative lookbehind; that may make it easier to respond.
– Daniel LeCheminant
Mar 13 '09 at 3:53
Consider posting the regex as it would look with a negative lookbehind; that may make it easier to respond.
– Daniel LeCheminant
Mar 13 '09 at 3:53
Consider posting the regex as it would look with a negative lookbehind; that may make it easier to respond.
– Daniel LeCheminant
Mar 13 '09 at 3:53
add a comment |
13 Answers
13
active
oldest
votes
Lookbehind Assertions got accepted into the ECMAScript specification in 2018. So far, it is only implemented in V8. So, if you're developing for a Chrome-only environment (such as Electron), or Node, you can start using lookbehinds today!
Positive lookbehind usage:
console.log(
"$9.99 €8.47".match(/(?<=$)d+(.d*)?/) // Matches "9.99"
);Negative lookbehind usage:
console.log(
"$9.99 €8.47".match(/(?<!$)d+(?:.d*)/) // Matches "8.47"
);Platform support:
- ✔V8
- ✔Google Chrome 62.0
- ✔Node.js 6.0 behind a flag and 9.0 without a flag
- ✔Google Chrome 62.0
- ❌Mozilla Firefox (SpiderMonkey) is working on it
- ❌Microsoft was working on it for Chakra, but the next version of Edge will be built on Chromium and will thus support it
- ❌Apple Safari (Webkit) is working on it
2
is there any polyfill?
– Killy
Jul 20 '18 at 16:47
@Killy there isn't as far as I know, and I doubt there ever will be, as creating one would be potentially very impractical (I.E. writing a full Regex implementation in JS)
– Okku
Jul 21 '18 at 19:00
What about using a babel plugin, is it possible to be compiled down to ES5 or already supported ES6?
– Stefan J
Oct 8 '18 at 10:12
@StefanJ no, for the same reasons as above
– Okku
Oct 8 '18 at 18:48
1
@IlpoOksanen I think you mean extending the RegEx implementation.. which is what polyfills do.... and there's nothing wrong with writing the logic in JavaScript
– neaumusic
Nov 27 '18 at 18:36
|
show 7 more comments
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
const reverse = s => s.split('').reverse().join('');
const test = (stringToTests, reversedRegexp) => stringToTests
.map(reverse)
.forEach((s,i) =>
const match = reversedRegexp.test(s);
console.log(stringToTests[i], match, 'token:', match ? reverse(reversedRegexp.exec(s)[0]) : 'Ø');
);
Example 1:
Following @andrew-ensley's question:
test(['jim', 'm', 'jam'], /m(?!([abcdefg]))/)
Outputs:
jim true token: m
m true token: m
jam false token: Ø
Example 2:
Following @neaumusic comment (match max-height but not line-height, the token being height):
test(['max-height', 'line-height'], /thgieh(?!(-enil))/)
Outputs:
max-height true token: height
line-height false token: Ø
32
the problem with this approach is that it doesn't work when you have both lookahead and lookbehind
– kboom
Oct 9 '14 at 11:25
3
can you please show a working example, say I want to matchmax-heightbut notline-heightand i only want the match to beheight
– neaumusic
May 14 '15 at 22:27
It does not help if the task is to replace two consecutive identical symbols (and no more than 2) that are not preceded with some symbol.''(?!()will replace the apostrophes in''(''test'''''''testfrom the other end, thus leaving(''test'NNNtestrather than(''testNNN'test.
– Wiktor Stribiżew
Apr 25 '16 at 11:20
I tried that and it shows me a pattern error.
– Thielicious
Sep 2 '18 at 15:25
add a comment |
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:
(?<!([abcdefg]))m
would translate to:
((?!([abcdefg])).|^)m
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.
2
This should be the correct answer. See:"So it would match the 'm' in 'jim' or 'm', but not 'jam'".replace(/(j(?!([abcdefg])).|^)m/g, "$1[MATCH]")returns"So it would match the 'm' in 'ji[MATCH]' or 'm', but not 'jam'"It is pretty simple and it works!
– Asrail
Aug 19 '15 at 2:21
add a comment |
Mijoja's strategy works for your specific case but not in general:
js>newString = "Fall ball bill balll llama".replace(/(ba)?ll/g,
function($0,$1) return $1?$0:"[match]";);
Fa[match] ball bi[match] balll [match]ama
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.
5
Ah, you are correct. However, this is a lot closer than I was before. I can accept this until something better comes along (like javascript actually implementing lookbehinds).
– Andrew Ensley
Mar 13 '09 at 15:38
add a comment |
Use
newString = string.replace(/([abcdefg])?m/, function($0,$1) return $1?$0:'m';);
9
This doesn't do anything:newStringwill always equalstring. Why so many upvotes?
– MikeM
Jan 3 '13 at 19:26
@MikeM: because the point is simply to demonstrate a matching technique.
– bug
Mar 12 '13 at 2:59
55
@bug. A demonstration that doesn't do anything is a strange kind of demonstration. The answer comes across as if it was just copy and pasted without any understanding of how it works. Thus the lack of accompanying explanation and the failure to demonstrate that anything has been matched.
– MikeM
Mar 12 '13 at 15:41
1
@MikeM: the rule of SO is, if it answers the question as written, it's correct. OP didn't specify a use case
– bug
Mar 26 '13 at 1:34
7
The concept is correct, but yes it's not demo'd very well. Try running this in the JS console..."Jim Jam Momm m".replace(/([abcdefg])?m/g, function($0, $1) return $1 ? $0 : '[match]'; );. It should returnJi[match] Jam Mo[match][match] [match]. But also note that as Jason mentioned below, it can fail on certain edge cases.
– Simon East
Sep 16 '14 at 4:24
|
show 1 more comment
You could define a non-capturing group by negating your character set:
(?:[^a-g])m
...which would match every m NOT preceded by any of those letters.
2
I think the match would actually also cover the preceding character.
– Sam
Sep 28 '13 at 6:37
3
^ this is true. A character class represents...a character! All your non-capturing group is doing is not making that value available in a replace context. Your expression is not saying "every m NOT preceded by any of those letters" it is saying "every m preceded by a character that is NOT any of those letters"
– Thomas McCabe
Mar 13 '14 at 22:13
4
For the answer to also solve the original problem (beginning of string), it must also include an option, so the resulting regex would be(?:[^a-g]|^)m. See regex101.com/r/jL1iW6/2 for running example.
– Johny Skovdal
Jan 18 '16 at 22:35
Using void logic does not always have the desired effect.
– GoldBishop
Aug 9 '17 at 13:49
add a comment |
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 :)
var re = /(?=(..|^.?)(ll))/g
// matches empty string position
// whenever this position is followed by
// a string of length equal or inferior (in case of "^")
// to "lookbehind" value
// + actual value we would want to match
, str = "Fall ball bill balll llama"
, str_done = str
, len_difference = 0
, doer = function (where_in_str, to_replace)
str_done = str_done.slice(0, where_in_str + len_difference)
+ "[match]"
+ str_done.slice(where_in_str + len_difference + to_replace.length)
len_difference = str_done.length - str.length
/* if str smaller:
len_difference will be positive
else will be negative
*/
/* the actual function that would do whatever we want to do
with the matches;
this above is only an example from Jason's */
/* function input of .replace(),
only there to test the value of $behind
and if negative, call doer() with interesting parameters */
, checker = function ($match, $behind, $after, $where, $str)
if ($behind !== "ba")
doer
(
$where + $behind.length
, $after
/* one will choose the interesting arguments
to give to the doer, it's only an example */
)
return $match // empty string anyhow, but well
str.replace(re, checker)
console.log(str_done)
my personal output:
Fa[match] ball bi[match] bal[match] [match]ama
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 before ll 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 of str.
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 on str, 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) outside checker is best, to avoid the same regex object to be created at each call for checker) 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. :)
add a comment |
This effectively does it
"jim".match(/[^a-g]m/)
> ["im"]
"jam".match(/[^a-g]m/)
> null
Search and replace example
"jim jam".replace(/([^a-g])m/g, "$1M")
> "jiM jam"
Note that the negative look-behind string must be 1 character long for this to work.
Not quite. In "jim", I don't want the "i"; just the "m". And"m".match(/[^a-g]m/)yeildsnullas well. I want the "m" in that case too.
– Andrew Ensley
Apr 13 '16 at 14:14
add a comment |
Using your case, if you want to replace m with something, e.g. convert it to uppercase M, you can negate set in capturing group.
match ([^a-g])m, replace with $1M
"jim jam".replace(/([^a-g])m/g, "$1M")
\jiM jam
([^a-g]) will match any char not(^) in a-g range, and store it in first capturing group, so you can access it with $1.
So we find im in jim and replace it with iM which results in jiM.
add a comment |
This is how I achieved str.split(/(?<!^)@/) for Node.js 8 (which doesn't support lookbehind):
str.split('').reverse().join('').split(/@(?!$)/).map(s => s.split('').reverse().join('')).reverse()
Works? Yes (unicode untested). Unpleasant? Yes.
add a comment |
As mentioned before, JavaScript allows lookbehinds now. In older browsers you still need a workaround.
I bet my head there is no way to find a regex without lookbehind that delivers the result exactly. All you can do is working with groups. Suppose you have a regex (?<!Before)Wanted, where Wanted is the regex you want to match and Before is the regex that counts out what should not precede the match. The best you can do is negate the regex Before and use the regex NotBefore(Wanted). The desired result is the first group $1.
In your case Before=[abcdefg] which is easy to negate NotBefore=[^abcdefg]. So the regex would be [^abcdefg](m). If you need the position of Wanted, you must group NotBefore too, so that the desired result is the second group.
If matches of the Before pattern have a fixed length n, that is, if the pattern contains no repetitive tokens, you can avoid negating the Before pattern and use the regular expression (?!Before).n(Wanted), but still have to use the first group or use the regular expression (?!Before)(.n)(Wanted) and use the second group. In this example, the pattern Before actually has a fixed length, namely 1, so use the regex (?![abcdefg]).(m) or (?![abcdefg])(.)(m). If you are interested in all matches, add the g flag, see my code snippet:
function TestSORegEx()
var s = "Donald Trump doesn't like jam, but Homer Simpson does.";
var reg = /(?![abcdefg])(.1)(m)/gm;
var out = "Matches and groups of the regex " +
"/(?![abcdefg])(.1)(m)/gm in ns = "" + s + """;
var match = reg.exec(s);
while(match)
var start = match.index + match[1].length;
out += "nWhole match: " + match[0] + ", starts at: " + match.index
+ ". Desired match: " + match[2] + ", starts at: " + start + ".";
match = reg.exec(s);
out += "nResulting string after statement s.replace(reg, "$1*$2*")n"
+ s.replace(reg, "$1*$2*");
alert(out);
add a comment |
/(?![abcdefg])[^abcdefg]m/gi
yes this is a trick.
5
The check(?![abcdefg])is totally redundant, since[^abcdefg]already does its job to prevent those character from matching.
– nhahtdh
Jan 15 '15 at 6:33
2
This will not match an 'm' with no preceding characters.
– Andrew Ensley
Apr 20 '15 at 15:27
add a comment |
This might help, depending on the context:
This matches the m in jim but not jam:
"jim jam".replace(/[a-g]m/g, "").match(/m/g)
This works purely for matching, but then I don't have the original string for any sort of manipulation. Very close.
– Andrew Ensley
Apr 13 '16 at 14:21
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f641407%2fjavascript-negative-lookbehind-equivalent%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
13 Answers
13
active
oldest
votes
13 Answers
13
active
oldest
votes
active
oldest
votes
active
oldest
votes
Lookbehind Assertions got accepted into the ECMAScript specification in 2018. So far, it is only implemented in V8. So, if you're developing for a Chrome-only environment (such as Electron), or Node, you can start using lookbehinds today!
Positive lookbehind usage:
console.log(
"$9.99 €8.47".match(/(?<=$)d+(.d*)?/) // Matches "9.99"
);Negative lookbehind usage:
console.log(
"$9.99 €8.47".match(/(?<!$)d+(?:.d*)/) // Matches "8.47"
);Platform support:
- ✔V8
- ✔Google Chrome 62.0
- ✔Node.js 6.0 behind a flag and 9.0 without a flag
- ✔Google Chrome 62.0
- ❌Mozilla Firefox (SpiderMonkey) is working on it
- ❌Microsoft was working on it for Chakra, but the next version of Edge will be built on Chromium and will thus support it
- ❌Apple Safari (Webkit) is working on it
2
is there any polyfill?
– Killy
Jul 20 '18 at 16:47
@Killy there isn't as far as I know, and I doubt there ever will be, as creating one would be potentially very impractical (I.E. writing a full Regex implementation in JS)
– Okku
Jul 21 '18 at 19:00
What about using a babel plugin, is it possible to be compiled down to ES5 or already supported ES6?
– Stefan J
Oct 8 '18 at 10:12
@StefanJ no, for the same reasons as above
– Okku
Oct 8 '18 at 18:48
1
@IlpoOksanen I think you mean extending the RegEx implementation.. which is what polyfills do.... and there's nothing wrong with writing the logic in JavaScript
– neaumusic
Nov 27 '18 at 18:36
|
show 7 more comments
Lookbehind Assertions got accepted into the ECMAScript specification in 2018. So far, it is only implemented in V8. So, if you're developing for a Chrome-only environment (such as Electron), or Node, you can start using lookbehinds today!
Positive lookbehind usage:
console.log(
"$9.99 €8.47".match(/(?<=$)d+(.d*)?/) // Matches "9.99"
);Negative lookbehind usage:
console.log(
"$9.99 €8.47".match(/(?<!$)d+(?:.d*)/) // Matches "8.47"
);Platform support:
- ✔V8
- ✔Google Chrome 62.0
- ✔Node.js 6.0 behind a flag and 9.0 without a flag
- ✔Google Chrome 62.0
- ❌Mozilla Firefox (SpiderMonkey) is working on it
- ❌Microsoft was working on it for Chakra, but the next version of Edge will be built on Chromium and will thus support it
- ❌Apple Safari (Webkit) is working on it
2
is there any polyfill?
– Killy
Jul 20 '18 at 16:47
@Killy there isn't as far as I know, and I doubt there ever will be, as creating one would be potentially very impractical (I.E. writing a full Regex implementation in JS)
– Okku
Jul 21 '18 at 19:00
What about using a babel plugin, is it possible to be compiled down to ES5 or already supported ES6?
– Stefan J
Oct 8 '18 at 10:12
@StefanJ no, for the same reasons as above
– Okku
Oct 8 '18 at 18:48
1
@IlpoOksanen I think you mean extending the RegEx implementation.. which is what polyfills do.... and there's nothing wrong with writing the logic in JavaScript
– neaumusic
Nov 27 '18 at 18:36
|
show 7 more comments
Lookbehind Assertions got accepted into the ECMAScript specification in 2018. So far, it is only implemented in V8. So, if you're developing for a Chrome-only environment (such as Electron), or Node, you can start using lookbehinds today!
Positive lookbehind usage:
console.log(
"$9.99 €8.47".match(/(?<=$)d+(.d*)?/) // Matches "9.99"
);Negative lookbehind usage:
console.log(
"$9.99 €8.47".match(/(?<!$)d+(?:.d*)/) // Matches "8.47"
);Platform support:
- ✔V8
- ✔Google Chrome 62.0
- ✔Node.js 6.0 behind a flag and 9.0 without a flag
- ✔Google Chrome 62.0
- ❌Mozilla Firefox (SpiderMonkey) is working on it
- ❌Microsoft was working on it for Chakra, but the next version of Edge will be built on Chromium and will thus support it
- ❌Apple Safari (Webkit) is working on it
Lookbehind Assertions got accepted into the ECMAScript specification in 2018. So far, it is only implemented in V8. So, if you're developing for a Chrome-only environment (such as Electron), or Node, you can start using lookbehinds today!
Positive lookbehind usage:
console.log(
"$9.99 €8.47".match(/(?<=$)d+(.d*)?/) // Matches "9.99"
);Negative lookbehind usage:
console.log(
"$9.99 €8.47".match(/(?<!$)d+(?:.d*)/) // Matches "8.47"
);Platform support:
- ✔V8
- ✔Google Chrome 62.0
- ✔Node.js 6.0 behind a flag and 9.0 without a flag
- ✔Google Chrome 62.0
- ❌Mozilla Firefox (SpiderMonkey) is working on it
- ❌Microsoft was working on it for Chakra, but the next version of Edge will be built on Chromium and will thus support it
- ❌Apple Safari (Webkit) is working on it
console.log(
"$9.99 €8.47".match(/(?<=$)d+(.d*)?/) // Matches "9.99"
);console.log(
"$9.99 €8.47".match(/(?<=$)d+(.d*)?/) // Matches "9.99"
);console.log(
"$9.99 €8.47".match(/(?<!$)d+(?:.d*)/) // Matches "8.47"
);console.log(
"$9.99 €8.47".match(/(?<!$)d+(?:.d*)/) // Matches "8.47"
);edited Jul 10 at 12:16
answered May 20 '18 at 12:32
OkkuOkku
4,7051 gold badge20 silver badges39 bronze badges
4,7051 gold badge20 silver badges39 bronze badges
2
is there any polyfill?
– Killy
Jul 20 '18 at 16:47
@Killy there isn't as far as I know, and I doubt there ever will be, as creating one would be potentially very impractical (I.E. writing a full Regex implementation in JS)
– Okku
Jul 21 '18 at 19:00
What about using a babel plugin, is it possible to be compiled down to ES5 or already supported ES6?
– Stefan J
Oct 8 '18 at 10:12
@StefanJ no, for the same reasons as above
– Okku
Oct 8 '18 at 18:48
1
@IlpoOksanen I think you mean extending the RegEx implementation.. which is what polyfills do.... and there's nothing wrong with writing the logic in JavaScript
– neaumusic
Nov 27 '18 at 18:36
|
show 7 more comments
2
is there any polyfill?
– Killy
Jul 20 '18 at 16:47
@Killy there isn't as far as I know, and I doubt there ever will be, as creating one would be potentially very impractical (I.E. writing a full Regex implementation in JS)
– Okku
Jul 21 '18 at 19:00
What about using a babel plugin, is it possible to be compiled down to ES5 or already supported ES6?
– Stefan J
Oct 8 '18 at 10:12
@StefanJ no, for the same reasons as above
– Okku
Oct 8 '18 at 18:48
1
@IlpoOksanen I think you mean extending the RegEx implementation.. which is what polyfills do.... and there's nothing wrong with writing the logic in JavaScript
– neaumusic
Nov 27 '18 at 18:36
2
2
is there any polyfill?
– Killy
Jul 20 '18 at 16:47
is there any polyfill?
– Killy
Jul 20 '18 at 16:47
@Killy there isn't as far as I know, and I doubt there ever will be, as creating one would be potentially very impractical (I.E. writing a full Regex implementation in JS)
– Okku
Jul 21 '18 at 19:00
@Killy there isn't as far as I know, and I doubt there ever will be, as creating one would be potentially very impractical (I.E. writing a full Regex implementation in JS)
– Okku
Jul 21 '18 at 19:00
What about using a babel plugin, is it possible to be compiled down to ES5 or already supported ES6?
– Stefan J
Oct 8 '18 at 10:12
What about using a babel plugin, is it possible to be compiled down to ES5 or already supported ES6?
– Stefan J
Oct 8 '18 at 10:12
@StefanJ no, for the same reasons as above
– Okku
Oct 8 '18 at 18:48
@StefanJ no, for the same reasons as above
– Okku
Oct 8 '18 at 18:48
1
1
@IlpoOksanen I think you mean extending the RegEx implementation.. which is what polyfills do.... and there's nothing wrong with writing the logic in JavaScript
– neaumusic
Nov 27 '18 at 18:36
@IlpoOksanen I think you mean extending the RegEx implementation.. which is what polyfills do.... and there's nothing wrong with writing the logic in JavaScript
– neaumusic
Nov 27 '18 at 18:36
|
show 7 more comments
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
const reverse = s => s.split('').reverse().join('');
const test = (stringToTests, reversedRegexp) => stringToTests
.map(reverse)
.forEach((s,i) =>
const match = reversedRegexp.test(s);
console.log(stringToTests[i], match, 'token:', match ? reverse(reversedRegexp.exec(s)[0]) : 'Ø');
);
Example 1:
Following @andrew-ensley's question:
test(['jim', 'm', 'jam'], /m(?!([abcdefg]))/)
Outputs:
jim true token: m
m true token: m
jam false token: Ø
Example 2:
Following @neaumusic comment (match max-height but not line-height, the token being height):
test(['max-height', 'line-height'], /thgieh(?!(-enil))/)
Outputs:
max-height true token: height
line-height false token: Ø
32
the problem with this approach is that it doesn't work when you have both lookahead and lookbehind
– kboom
Oct 9 '14 at 11:25
3
can you please show a working example, say I want to matchmax-heightbut notline-heightand i only want the match to beheight
– neaumusic
May 14 '15 at 22:27
It does not help if the task is to replace two consecutive identical symbols (and no more than 2) that are not preceded with some symbol.''(?!()will replace the apostrophes in''(''test'''''''testfrom the other end, thus leaving(''test'NNNtestrather than(''testNNN'test.
– Wiktor Stribiżew
Apr 25 '16 at 11:20
I tried that and it shows me a pattern error.
– Thielicious
Sep 2 '18 at 15:25
add a comment |
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
const reverse = s => s.split('').reverse().join('');
const test = (stringToTests, reversedRegexp) => stringToTests
.map(reverse)
.forEach((s,i) =>
const match = reversedRegexp.test(s);
console.log(stringToTests[i], match, 'token:', match ? reverse(reversedRegexp.exec(s)[0]) : 'Ø');
);
Example 1:
Following @andrew-ensley's question:
test(['jim', 'm', 'jam'], /m(?!([abcdefg]))/)
Outputs:
jim true token: m
m true token: m
jam false token: Ø
Example 2:
Following @neaumusic comment (match max-height but not line-height, the token being height):
test(['max-height', 'line-height'], /thgieh(?!(-enil))/)
Outputs:
max-height true token: height
line-height false token: Ø
32
the problem with this approach is that it doesn't work when you have both lookahead and lookbehind
– kboom
Oct 9 '14 at 11:25
3
can you please show a working example, say I want to matchmax-heightbut notline-heightand i only want the match to beheight
– neaumusic
May 14 '15 at 22:27
It does not help if the task is to replace two consecutive identical symbols (and no more than 2) that are not preceded with some symbol.''(?!()will replace the apostrophes in''(''test'''''''testfrom the other end, thus leaving(''test'NNNtestrather than(''testNNN'test.
– Wiktor Stribiżew
Apr 25 '16 at 11:20
I tried that and it shows me a pattern error.
– Thielicious
Sep 2 '18 at 15:25
add a comment |
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
const reverse = s => s.split('').reverse().join('');
const test = (stringToTests, reversedRegexp) => stringToTests
.map(reverse)
.forEach((s,i) =>
const match = reversedRegexp.test(s);
console.log(stringToTests[i], match, 'token:', match ? reverse(reversedRegexp.exec(s)[0]) : 'Ø');
);
Example 1:
Following @andrew-ensley's question:
test(['jim', 'm', 'jam'], /m(?!([abcdefg]))/)
Outputs:
jim true token: m
m true token: m
jam false token: Ø
Example 2:
Following @neaumusic comment (match max-height but not line-height, the token being height):
test(['max-height', 'line-height'], /thgieh(?!(-enil))/)
Outputs:
max-height true token: height
line-height false token: Ø
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
const reverse = s => s.split('').reverse().join('');
const test = (stringToTests, reversedRegexp) => stringToTests
.map(reverse)
.forEach((s,i) =>
const match = reversedRegexp.test(s);
console.log(stringToTests[i], match, 'token:', match ? reverse(reversedRegexp.exec(s)[0]) : 'Ø');
);
Example 1:
Following @andrew-ensley's question:
test(['jim', 'm', 'jam'], /m(?!([abcdefg]))/)
Outputs:
jim true token: m
m true token: m
jam false token: Ø
Example 2:
Following @neaumusic comment (match max-height but not line-height, the token being height):
test(['max-height', 'line-height'], /thgieh(?!(-enil))/)
Outputs:
max-height true token: height
line-height false token: Ø
edited Nov 27 '18 at 19:04
neaumusic
5,5152 gold badges31 silver badges50 bronze badges
5,5152 gold badges31 silver badges50 bronze badges
answered Jul 5 '12 at 15:02
JBEJBE
7,1933 gold badges42 silver badges39 bronze badges
7,1933 gold badges42 silver badges39 bronze badges
32
the problem with this approach is that it doesn't work when you have both lookahead and lookbehind
– kboom
Oct 9 '14 at 11:25
3
can you please show a working example, say I want to matchmax-heightbut notline-heightand i only want the match to beheight
– neaumusic
May 14 '15 at 22:27
It does not help if the task is to replace two consecutive identical symbols (and no more than 2) that are not preceded with some symbol.''(?!()will replace the apostrophes in''(''test'''''''testfrom the other end, thus leaving(''test'NNNtestrather than(''testNNN'test.
– Wiktor Stribiżew
Apr 25 '16 at 11:20
I tried that and it shows me a pattern error.
– Thielicious
Sep 2 '18 at 15:25
add a comment |
32
the problem with this approach is that it doesn't work when you have both lookahead and lookbehind
– kboom
Oct 9 '14 at 11:25
3
can you please show a working example, say I want to matchmax-heightbut notline-heightand i only want the match to beheight
– neaumusic
May 14 '15 at 22:27
It does not help if the task is to replace two consecutive identical symbols (and no more than 2) that are not preceded with some symbol.''(?!()will replace the apostrophes in''(''test'''''''testfrom the other end, thus leaving(''test'NNNtestrather than(''testNNN'test.
– Wiktor Stribiżew
Apr 25 '16 at 11:20
I tried that and it shows me a pattern error.
– Thielicious
Sep 2 '18 at 15:25
32
32
the problem with this approach is that it doesn't work when you have both lookahead and lookbehind
– kboom
Oct 9 '14 at 11:25
the problem with this approach is that it doesn't work when you have both lookahead and lookbehind
– kboom
Oct 9 '14 at 11:25
3
3
can you please show a working example, say I want to match
max-height but not line-height and i only want the match to be height– neaumusic
May 14 '15 at 22:27
can you please show a working example, say I want to match
max-height but not line-height and i only want the match to be height– neaumusic
May 14 '15 at 22:27
It does not help if the task is to replace two consecutive identical symbols (and no more than 2) that are not preceded with some symbol.
''(?!() will replace the apostrophes in ''(''test'''''''test from the other end, thus leaving (''test'NNNtest rather than (''testNNN'test.– Wiktor Stribiżew
Apr 25 '16 at 11:20
It does not help if the task is to replace two consecutive identical symbols (and no more than 2) that are not preceded with some symbol.
''(?!() will replace the apostrophes in ''(''test'''''''test from the other end, thus leaving (''test'NNNtest rather than (''testNNN'test.– Wiktor Stribiżew
Apr 25 '16 at 11:20
I tried that and it shows me a pattern error.
– Thielicious
Sep 2 '18 at 15:25
I tried that and it shows me a pattern error.
– Thielicious
Sep 2 '18 at 15:25
add a comment |
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:
(?<!([abcdefg]))m
would translate to:
((?!([abcdefg])).|^)m
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.
2
This should be the correct answer. See:"So it would match the 'm' in 'jim' or 'm', but not 'jam'".replace(/(j(?!([abcdefg])).|^)m/g, "$1[MATCH]")returns"So it would match the 'm' in 'ji[MATCH]' or 'm', but not 'jam'"It is pretty simple and it works!
– Asrail
Aug 19 '15 at 2:21
add a comment |
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:
(?<!([abcdefg]))m
would translate to:
((?!([abcdefg])).|^)m
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.
2
This should be the correct answer. See:"So it would match the 'm' in 'jim' or 'm', but not 'jam'".replace(/(j(?!([abcdefg])).|^)m/g, "$1[MATCH]")returns"So it would match the 'm' in 'ji[MATCH]' or 'm', but not 'jam'"It is pretty simple and it works!
– Asrail
Aug 19 '15 at 2:21
add a comment |
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:
(?<!([abcdefg]))m
would translate to:
((?!([abcdefg])).|^)m
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.
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:
(?<!([abcdefg]))m
would translate to:
((?!([abcdefg])).|^)m
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.
edited Mar 11 '15 at 7:42
nhahtdh
49.1k13 gold badges101 silver badges136 bronze badges
49.1k13 gold badges101 silver badges136 bronze badges
answered Nov 30 '14 at 13:20
Kamil SzotKamil Szot
12.3k6 gold badges47 silver badges57 bronze badges
12.3k6 gold badges47 silver badges57 bronze badges
2
This should be the correct answer. See:"So it would match the 'm' in 'jim' or 'm', but not 'jam'".replace(/(j(?!([abcdefg])).|^)m/g, "$1[MATCH]")returns"So it would match the 'm' in 'ji[MATCH]' or 'm', but not 'jam'"It is pretty simple and it works!
– Asrail
Aug 19 '15 at 2:21
add a comment |
2
This should be the correct answer. See:"So it would match the 'm' in 'jim' or 'm', but not 'jam'".replace(/(j(?!([abcdefg])).|^)m/g, "$1[MATCH]")returns"So it would match the 'm' in 'ji[MATCH]' or 'm', but not 'jam'"It is pretty simple and it works!
– Asrail
Aug 19 '15 at 2:21
2
2
This should be the correct answer. See:
"So it would match the 'm' in 'jim' or 'm', but not 'jam'".replace(/(j(?!([abcdefg])).|^)m/g, "$1[MATCH]") returns "So it would match the 'm' in 'ji[MATCH]' or 'm', but not 'jam'" It is pretty simple and it works!– Asrail
Aug 19 '15 at 2:21
This should be the correct answer. See:
"So it would match the 'm' in 'jim' or 'm', but not 'jam'".replace(/(j(?!([abcdefg])).|^)m/g, "$1[MATCH]") returns "So it would match the 'm' in 'ji[MATCH]' or 'm', but not 'jam'" It is pretty simple and it works!– Asrail
Aug 19 '15 at 2:21
add a comment |
Mijoja's strategy works for your specific case but not in general:
js>newString = "Fall ball bill balll llama".replace(/(ba)?ll/g,
function($0,$1) return $1?$0:"[match]";);
Fa[match] ball bi[match] balll [match]ama
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.
5
Ah, you are correct. However, this is a lot closer than I was before. I can accept this until something better comes along (like javascript actually implementing lookbehinds).
– Andrew Ensley
Mar 13 '09 at 15:38
add a comment |
Mijoja's strategy works for your specific case but not in general:
js>newString = "Fall ball bill balll llama".replace(/(ba)?ll/g,
function($0,$1) return $1?$0:"[match]";);
Fa[match] ball bi[match] balll [match]ama
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.
5
Ah, you are correct. However, this is a lot closer than I was before. I can accept this until something better comes along (like javascript actually implementing lookbehinds).
– Andrew Ensley
Mar 13 '09 at 15:38
add a comment |
Mijoja's strategy works for your specific case but not in general:
js>newString = "Fall ball bill balll llama".replace(/(ba)?ll/g,
function($0,$1) return $1?$0:"[match]";);
Fa[match] ball bi[match] balll [match]ama
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.
Mijoja's strategy works for your specific case but not in general:
js>newString = "Fall ball bill balll llama".replace(/(ba)?ll/g,
function($0,$1) return $1?$0:"[match]";);
Fa[match] ball bi[match] balll [match]ama
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.
edited Jan 15 '15 at 21:53
answered Mar 13 '09 at 13:38
Jason SJason S
111k138 gold badges502 silver badges837 bronze badges
111k138 gold badges502 silver badges837 bronze badges
5
Ah, you are correct. However, this is a lot closer than I was before. I can accept this until something better comes along (like javascript actually implementing lookbehinds).
– Andrew Ensley
Mar 13 '09 at 15:38
add a comment |
5
Ah, you are correct. However, this is a lot closer than I was before. I can accept this until something better comes along (like javascript actually implementing lookbehinds).
– Andrew Ensley
Mar 13 '09 at 15:38
5
5
Ah, you are correct. However, this is a lot closer than I was before. I can accept this until something better comes along (like javascript actually implementing lookbehinds).
– Andrew Ensley
Mar 13 '09 at 15:38
Ah, you are correct. However, this is a lot closer than I was before. I can accept this until something better comes along (like javascript actually implementing lookbehinds).
– Andrew Ensley
Mar 13 '09 at 15:38
add a comment |
Use
newString = string.replace(/([abcdefg])?m/, function($0,$1) return $1?$0:'m';);
9
This doesn't do anything:newStringwill always equalstring. Why so many upvotes?
– MikeM
Jan 3 '13 at 19:26
@MikeM: because the point is simply to demonstrate a matching technique.
– bug
Mar 12 '13 at 2:59
55
@bug. A demonstration that doesn't do anything is a strange kind of demonstration. The answer comes across as if it was just copy and pasted without any understanding of how it works. Thus the lack of accompanying explanation and the failure to demonstrate that anything has been matched.
– MikeM
Mar 12 '13 at 15:41
1
@MikeM: the rule of SO is, if it answers the question as written, it's correct. OP didn't specify a use case
– bug
Mar 26 '13 at 1:34
7
The concept is correct, but yes it's not demo'd very well. Try running this in the JS console..."Jim Jam Momm m".replace(/([abcdefg])?m/g, function($0, $1) return $1 ? $0 : '[match]'; );. It should returnJi[match] Jam Mo[match][match] [match]. But also note that as Jason mentioned below, it can fail on certain edge cases.
– Simon East
Sep 16 '14 at 4:24
|
show 1 more comment
Use
newString = string.replace(/([abcdefg])?m/, function($0,$1) return $1?$0:'m';);
9
This doesn't do anything:newStringwill always equalstring. Why so many upvotes?
– MikeM
Jan 3 '13 at 19:26
@MikeM: because the point is simply to demonstrate a matching technique.
– bug
Mar 12 '13 at 2:59
55
@bug. A demonstration that doesn't do anything is a strange kind of demonstration. The answer comes across as if it was just copy and pasted without any understanding of how it works. Thus the lack of accompanying explanation and the failure to demonstrate that anything has been matched.
– MikeM
Mar 12 '13 at 15:41
1
@MikeM: the rule of SO is, if it answers the question as written, it's correct. OP didn't specify a use case
– bug
Mar 26 '13 at 1:34
7
The concept is correct, but yes it's not demo'd very well. Try running this in the JS console..."Jim Jam Momm m".replace(/([abcdefg])?m/g, function($0, $1) return $1 ? $0 : '[match]'; );. It should returnJi[match] Jam Mo[match][match] [match]. But also note that as Jason mentioned below, it can fail on certain edge cases.
– Simon East
Sep 16 '14 at 4:24
|
show 1 more comment
Use
newString = string.replace(/([abcdefg])?m/, function($0,$1) return $1?$0:'m';);
Use
newString = string.replace(/([abcdefg])?m/, function($0,$1) return $1?$0:'m';);
answered Mar 13 '09 at 4:11
MijojaMijoja
6536 silver badges7 bronze badges
6536 silver badges7 bronze badges
9
This doesn't do anything:newStringwill always equalstring. Why so many upvotes?
– MikeM
Jan 3 '13 at 19:26
@MikeM: because the point is simply to demonstrate a matching technique.
– bug
Mar 12 '13 at 2:59
55
@bug. A demonstration that doesn't do anything is a strange kind of demonstration. The answer comes across as if it was just copy and pasted without any understanding of how it works. Thus the lack of accompanying explanation and the failure to demonstrate that anything has been matched.
– MikeM
Mar 12 '13 at 15:41
1
@MikeM: the rule of SO is, if it answers the question as written, it's correct. OP didn't specify a use case
– bug
Mar 26 '13 at 1:34
7
The concept is correct, but yes it's not demo'd very well. Try running this in the JS console..."Jim Jam Momm m".replace(/([abcdefg])?m/g, function($0, $1) return $1 ? $0 : '[match]'; );. It should returnJi[match] Jam Mo[match][match] [match]. But also note that as Jason mentioned below, it can fail on certain edge cases.
– Simon East
Sep 16 '14 at 4:24
|
show 1 more comment
9
This doesn't do anything:newStringwill always equalstring. Why so many upvotes?
– MikeM
Jan 3 '13 at 19:26
@MikeM: because the point is simply to demonstrate a matching technique.
– bug
Mar 12 '13 at 2:59
55
@bug. A demonstration that doesn't do anything is a strange kind of demonstration. The answer comes across as if it was just copy and pasted without any understanding of how it works. Thus the lack of accompanying explanation and the failure to demonstrate that anything has been matched.
– MikeM
Mar 12 '13 at 15:41
1
@MikeM: the rule of SO is, if it answers the question as written, it's correct. OP didn't specify a use case
– bug
Mar 26 '13 at 1:34
7
The concept is correct, but yes it's not demo'd very well. Try running this in the JS console..."Jim Jam Momm m".replace(/([abcdefg])?m/g, function($0, $1) return $1 ? $0 : '[match]'; );. It should returnJi[match] Jam Mo[match][match] [match]. But also note that as Jason mentioned below, it can fail on certain edge cases.
– Simon East
Sep 16 '14 at 4:24
9
9
This doesn't do anything:
newString will always equal string. Why so many upvotes?– MikeM
Jan 3 '13 at 19:26
This doesn't do anything:
newString will always equal string. Why so many upvotes?– MikeM
Jan 3 '13 at 19:26
@MikeM: because the point is simply to demonstrate a matching technique.
– bug
Mar 12 '13 at 2:59
@MikeM: because the point is simply to demonstrate a matching technique.
– bug
Mar 12 '13 at 2:59
55
55
@bug. A demonstration that doesn't do anything is a strange kind of demonstration. The answer comes across as if it was just copy and pasted without any understanding of how it works. Thus the lack of accompanying explanation and the failure to demonstrate that anything has been matched.
– MikeM
Mar 12 '13 at 15:41
@bug. A demonstration that doesn't do anything is a strange kind of demonstration. The answer comes across as if it was just copy and pasted without any understanding of how it works. Thus the lack of accompanying explanation and the failure to demonstrate that anything has been matched.
– MikeM
Mar 12 '13 at 15:41
1
1
@MikeM: the rule of SO is, if it answers the question as written, it's correct. OP didn't specify a use case
– bug
Mar 26 '13 at 1:34
@MikeM: the rule of SO is, if it answers the question as written, it's correct. OP didn't specify a use case
– bug
Mar 26 '13 at 1:34
7
7
The concept is correct, but yes it's not demo'd very well. Try running this in the JS console...
"Jim Jam Momm m".replace(/([abcdefg])?m/g, function($0, $1) return $1 ? $0 : '[match]'; );. It should return Ji[match] Jam Mo[match][match] [match]. But also note that as Jason mentioned below, it can fail on certain edge cases.– Simon East
Sep 16 '14 at 4:24
The concept is correct, but yes it's not demo'd very well. Try running this in the JS console...
"Jim Jam Momm m".replace(/([abcdefg])?m/g, function($0, $1) return $1 ? $0 : '[match]'; );. It should return Ji[match] Jam Mo[match][match] [match]. But also note that as Jason mentioned below, it can fail on certain edge cases.– Simon East
Sep 16 '14 at 4:24
|
show 1 more comment
You could define a non-capturing group by negating your character set:
(?:[^a-g])m
...which would match every m NOT preceded by any of those letters.
2
I think the match would actually also cover the preceding character.
– Sam
Sep 28 '13 at 6:37
3
^ this is true. A character class represents...a character! All your non-capturing group is doing is not making that value available in a replace context. Your expression is not saying "every m NOT preceded by any of those letters" it is saying "every m preceded by a character that is NOT any of those letters"
– Thomas McCabe
Mar 13 '14 at 22:13
4
For the answer to also solve the original problem (beginning of string), it must also include an option, so the resulting regex would be(?:[^a-g]|^)m. See regex101.com/r/jL1iW6/2 for running example.
– Johny Skovdal
Jan 18 '16 at 22:35
Using void logic does not always have the desired effect.
– GoldBishop
Aug 9 '17 at 13:49
add a comment |
You could define a non-capturing group by negating your character set:
(?:[^a-g])m
...which would match every m NOT preceded by any of those letters.
2
I think the match would actually also cover the preceding character.
– Sam
Sep 28 '13 at 6:37
3
^ this is true. A character class represents...a character! All your non-capturing group is doing is not making that value available in a replace context. Your expression is not saying "every m NOT preceded by any of those letters" it is saying "every m preceded by a character that is NOT any of those letters"
– Thomas McCabe
Mar 13 '14 at 22:13
4
For the answer to also solve the original problem (beginning of string), it must also include an option, so the resulting regex would be(?:[^a-g]|^)m. See regex101.com/r/jL1iW6/2 for running example.
– Johny Skovdal
Jan 18 '16 at 22:35
Using void logic does not always have the desired effect.
– GoldBishop
Aug 9 '17 at 13:49
add a comment |
You could define a non-capturing group by negating your character set:
(?:[^a-g])m
...which would match every m NOT preceded by any of those letters.
You could define a non-capturing group by negating your character set:
(?:[^a-g])m
...which would match every m NOT preceded by any of those letters.
edited Apr 12 '16 at 1:51
Alan Moore
62.9k10 gold badges82 silver badges138 bronze badges
62.9k10 gold badges82 silver badges138 bronze badges
answered Aug 23 '13 at 0:13
Klemen SlavičKlemen Slavič
18.3k2 gold badges27 silver badges42 bronze badges
18.3k2 gold badges27 silver badges42 bronze badges
2
I think the match would actually also cover the preceding character.
– Sam
Sep 28 '13 at 6:37
3
^ this is true. A character class represents...a character! All your non-capturing group is doing is not making that value available in a replace context. Your expression is not saying "every m NOT preceded by any of those letters" it is saying "every m preceded by a character that is NOT any of those letters"
– Thomas McCabe
Mar 13 '14 at 22:13
4
For the answer to also solve the original problem (beginning of string), it must also include an option, so the resulting regex would be(?:[^a-g]|^)m. See regex101.com/r/jL1iW6/2 for running example.
– Johny Skovdal
Jan 18 '16 at 22:35
Using void logic does not always have the desired effect.
– GoldBishop
Aug 9 '17 at 13:49
add a comment |
2
I think the match would actually also cover the preceding character.
– Sam
Sep 28 '13 at 6:37
3
^ this is true. A character class represents...a character! All your non-capturing group is doing is not making that value available in a replace context. Your expression is not saying "every m NOT preceded by any of those letters" it is saying "every m preceded by a character that is NOT any of those letters"
– Thomas McCabe
Mar 13 '14 at 22:13
4
For the answer to also solve the original problem (beginning of string), it must also include an option, so the resulting regex would be(?:[^a-g]|^)m. See regex101.com/r/jL1iW6/2 for running example.
– Johny Skovdal
Jan 18 '16 at 22:35
Using void logic does not always have the desired effect.
– GoldBishop
Aug 9 '17 at 13:49
2
2
I think the match would actually also cover the preceding character.
– Sam
Sep 28 '13 at 6:37
I think the match would actually also cover the preceding character.
– Sam
Sep 28 '13 at 6:37
3
3
^ this is true. A character class represents...a character! All your non-capturing group is doing is not making that value available in a replace context. Your expression is not saying "every m NOT preceded by any of those letters" it is saying "every m preceded by a character that is NOT any of those letters"
– Thomas McCabe
Mar 13 '14 at 22:13
^ this is true. A character class represents...a character! All your non-capturing group is doing is not making that value available in a replace context. Your expression is not saying "every m NOT preceded by any of those letters" it is saying "every m preceded by a character that is NOT any of those letters"
– Thomas McCabe
Mar 13 '14 at 22:13
4
4
For the answer to also solve the original problem (beginning of string), it must also include an option, so the resulting regex would be
(?:[^a-g]|^)m. See regex101.com/r/jL1iW6/2 for running example.– Johny Skovdal
Jan 18 '16 at 22:35
For the answer to also solve the original problem (beginning of string), it must also include an option, so the resulting regex would be
(?:[^a-g]|^)m. See regex101.com/r/jL1iW6/2 for running example.– Johny Skovdal
Jan 18 '16 at 22:35
Using void logic does not always have the desired effect.
– GoldBishop
Aug 9 '17 at 13:49
Using void logic does not always have the desired effect.
– GoldBishop
Aug 9 '17 at 13:49
add a comment |
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 :)
var re = /(?=(..|^.?)(ll))/g
// matches empty string position
// whenever this position is followed by
// a string of length equal or inferior (in case of "^")
// to "lookbehind" value
// + actual value we would want to match
, str = "Fall ball bill balll llama"
, str_done = str
, len_difference = 0
, doer = function (where_in_str, to_replace)
str_done = str_done.slice(0, where_in_str + len_difference)
+ "[match]"
+ str_done.slice(where_in_str + len_difference + to_replace.length)
len_difference = str_done.length - str.length
/* if str smaller:
len_difference will be positive
else will be negative
*/
/* the actual function that would do whatever we want to do
with the matches;
this above is only an example from Jason's */
/* function input of .replace(),
only there to test the value of $behind
and if negative, call doer() with interesting parameters */
, checker = function ($match, $behind, $after, $where, $str)
if ($behind !== "ba")
doer
(
$where + $behind.length
, $after
/* one will choose the interesting arguments
to give to the doer, it's only an example */
)
return $match // empty string anyhow, but well
str.replace(re, checker)
console.log(str_done)
my personal output:
Fa[match] ball bi[match] bal[match] [match]ama
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 before ll 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 of str.
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 on str, 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) outside checker is best, to avoid the same regex object to be created at each call for checker) 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. :)
add a comment |
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 :)
var re = /(?=(..|^.?)(ll))/g
// matches empty string position
// whenever this position is followed by
// a string of length equal or inferior (in case of "^")
// to "lookbehind" value
// + actual value we would want to match
, str = "Fall ball bill balll llama"
, str_done = str
, len_difference = 0
, doer = function (where_in_str, to_replace)
str_done = str_done.slice(0, where_in_str + len_difference)
+ "[match]"
+ str_done.slice(where_in_str + len_difference + to_replace.length)
len_difference = str_done.length - str.length
/* if str smaller:
len_difference will be positive
else will be negative
*/
/* the actual function that would do whatever we want to do
with the matches;
this above is only an example from Jason's */
/* function input of .replace(),
only there to test the value of $behind
and if negative, call doer() with interesting parameters */
, checker = function ($match, $behind, $after, $where, $str)
if ($behind !== "ba")
doer
(
$where + $behind.length
, $after
/* one will choose the interesting arguments
to give to the doer, it's only an example */
)
return $match // empty string anyhow, but well
str.replace(re, checker)
console.log(str_done)
my personal output:
Fa[match] ball bi[match] bal[match] [match]ama
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 before ll 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 of str.
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 on str, 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) outside checker is best, to avoid the same regex object to be created at each call for checker) 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. :)
add a comment |
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 :)
var re = /(?=(..|^.?)(ll))/g
// matches empty string position
// whenever this position is followed by
// a string of length equal or inferior (in case of "^")
// to "lookbehind" value
// + actual value we would want to match
, str = "Fall ball bill balll llama"
, str_done = str
, len_difference = 0
, doer = function (where_in_str, to_replace)
str_done = str_done.slice(0, where_in_str + len_difference)
+ "[match]"
+ str_done.slice(where_in_str + len_difference + to_replace.length)
len_difference = str_done.length - str.length
/* if str smaller:
len_difference will be positive
else will be negative
*/
/* the actual function that would do whatever we want to do
with the matches;
this above is only an example from Jason's */
/* function input of .replace(),
only there to test the value of $behind
and if negative, call doer() with interesting parameters */
, checker = function ($match, $behind, $after, $where, $str)
if ($behind !== "ba")
doer
(
$where + $behind.length
, $after
/* one will choose the interesting arguments
to give to the doer, it's only an example */
)
return $match // empty string anyhow, but well
str.replace(re, checker)
console.log(str_done)
my personal output:
Fa[match] ball bi[match] bal[match] [match]ama
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 before ll 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 of str.
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 on str, 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) outside checker is best, to avoid the same regex object to be created at each call for checker) 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. :)
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 :)
var re = /(?=(..|^.?)(ll))/g
// matches empty string position
// whenever this position is followed by
// a string of length equal or inferior (in case of "^")
// to "lookbehind" value
// + actual value we would want to match
, str = "Fall ball bill balll llama"
, str_done = str
, len_difference = 0
, doer = function (where_in_str, to_replace)
str_done = str_done.slice(0, where_in_str + len_difference)
+ "[match]"
+ str_done.slice(where_in_str + len_difference + to_replace.length)
len_difference = str_done.length - str.length
/* if str smaller:
len_difference will be positive
else will be negative
*/
/* the actual function that would do whatever we want to do
with the matches;
this above is only an example from Jason's */
/* function input of .replace(),
only there to test the value of $behind
and if negative, call doer() with interesting parameters */
, checker = function ($match, $behind, $after, $where, $str)
if ($behind !== "ba")
doer
(
$where + $behind.length
, $after
/* one will choose the interesting arguments
to give to the doer, it's only an example */
)
return $match // empty string anyhow, but well
str.replace(re, checker)
console.log(str_done)
my personal output:
Fa[match] ball bi[match] bal[match] [match]ama
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 before ll 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 of str.
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 on str, 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) outside checker is best, to avoid the same regex object to be created at each call for checker) 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. :)
edited Apr 19 '15 at 8:42
answered Apr 19 '15 at 7:06
Homer SimpsonHomer Simpson
135 bronze badges
135 bronze badges
add a comment |
add a comment |
This effectively does it
"jim".match(/[^a-g]m/)
> ["im"]
"jam".match(/[^a-g]m/)
> null
Search and replace example
"jim jam".replace(/([^a-g])m/g, "$1M")
> "jiM jam"
Note that the negative look-behind string must be 1 character long for this to work.
Not quite. In "jim", I don't want the "i"; just the "m". And"m".match(/[^a-g]m/)yeildsnullas well. I want the "m" in that case too.
– Andrew Ensley
Apr 13 '16 at 14:14
add a comment |
This effectively does it
"jim".match(/[^a-g]m/)
> ["im"]
"jam".match(/[^a-g]m/)
> null
Search and replace example
"jim jam".replace(/([^a-g])m/g, "$1M")
> "jiM jam"
Note that the negative look-behind string must be 1 character long for this to work.
Not quite. In "jim", I don't want the "i"; just the "m". And"m".match(/[^a-g]m/)yeildsnullas well. I want the "m" in that case too.
– Andrew Ensley
Apr 13 '16 at 14:14
add a comment |
This effectively does it
"jim".match(/[^a-g]m/)
> ["im"]
"jam".match(/[^a-g]m/)
> null
Search and replace example
"jim jam".replace(/([^a-g])m/g, "$1M")
> "jiM jam"
Note that the negative look-behind string must be 1 character long for this to work.
This effectively does it
"jim".match(/[^a-g]m/)
> ["im"]
"jam".match(/[^a-g]m/)
> null
Search and replace example
"jim jam".replace(/([^a-g])m/g, "$1M")
> "jiM jam"
Note that the negative look-behind string must be 1 character long for this to work.
answered Apr 12 '16 at 0:18
Curtis YallopCurtis Yallop
4,5563 gold badges26 silver badges25 bronze badges
4,5563 gold badges26 silver badges25 bronze badges
Not quite. In "jim", I don't want the "i"; just the "m". And"m".match(/[^a-g]m/)yeildsnullas well. I want the "m" in that case too.
– Andrew Ensley
Apr 13 '16 at 14:14
add a comment |
Not quite. In "jim", I don't want the "i"; just the "m". And"m".match(/[^a-g]m/)yeildsnullas well. I want the "m" in that case too.
– Andrew Ensley
Apr 13 '16 at 14:14
Not quite. In "jim", I don't want the "i"; just the "m". And
"m".match(/[^a-g]m/) yeilds null as well. I want the "m" in that case too.– Andrew Ensley
Apr 13 '16 at 14:14
Not quite. In "jim", I don't want the "i"; just the "m". And
"m".match(/[^a-g]m/) yeilds null as well. I want the "m" in that case too.– Andrew Ensley
Apr 13 '16 at 14:14
add a comment |
Using your case, if you want to replace m with something, e.g. convert it to uppercase M, you can negate set in capturing group.
match ([^a-g])m, replace with $1M
"jim jam".replace(/([^a-g])m/g, "$1M")
\jiM jam
([^a-g]) will match any char not(^) in a-g range, and store it in first capturing group, so you can access it with $1.
So we find im in jim and replace it with iM which results in jiM.
add a comment |
Using your case, if you want to replace m with something, e.g. convert it to uppercase M, you can negate set in capturing group.
match ([^a-g])m, replace with $1M
"jim jam".replace(/([^a-g])m/g, "$1M")
\jiM jam
([^a-g]) will match any char not(^) in a-g range, and store it in first capturing group, so you can access it with $1.
So we find im in jim and replace it with iM which results in jiM.
add a comment |
Using your case, if you want to replace m with something, e.g. convert it to uppercase M, you can negate set in capturing group.
match ([^a-g])m, replace with $1M
"jim jam".replace(/([^a-g])m/g, "$1M")
\jiM jam
([^a-g]) will match any char not(^) in a-g range, and store it in first capturing group, so you can access it with $1.
So we find im in jim and replace it with iM which results in jiM.
Using your case, if you want to replace m with something, e.g. convert it to uppercase M, you can negate set in capturing group.
match ([^a-g])m, replace with $1M
"jim jam".replace(/([^a-g])m/g, "$1M")
\jiM jam
([^a-g]) will match any char not(^) in a-g range, and store it in first capturing group, so you can access it with $1.
So we find im in jim and replace it with iM which results in jiM.
answered Feb 16 '18 at 13:28
TraxoTraxo
7,6002 gold badges30 silver badges56 bronze badges
7,6002 gold badges30 silver badges56 bronze badges
add a comment |
add a comment |
This is how I achieved str.split(/(?<!^)@/) for Node.js 8 (which doesn't support lookbehind):
str.split('').reverse().join('').split(/@(?!$)/).map(s => s.split('').reverse().join('')).reverse()
Works? Yes (unicode untested). Unpleasant? Yes.
add a comment |
This is how I achieved str.split(/(?<!^)@/) for Node.js 8 (which doesn't support lookbehind):
str.split('').reverse().join('').split(/@(?!$)/).map(s => s.split('').reverse().join('')).reverse()
Works? Yes (unicode untested). Unpleasant? Yes.
add a comment |
This is how I achieved str.split(/(?<!^)@/) for Node.js 8 (which doesn't support lookbehind):
str.split('').reverse().join('').split(/@(?!$)/).map(s => s.split('').reverse().join('')).reverse()
Works? Yes (unicode untested). Unpleasant? Yes.
This is how I achieved str.split(/(?<!^)@/) for Node.js 8 (which doesn't support lookbehind):
str.split('').reverse().join('').split(/@(?!$)/).map(s => s.split('').reverse().join('')).reverse()
Works? Yes (unicode untested). Unpleasant? Yes.
answered Apr 1 at 19:43
Fishrock123Fishrock123
532 silver badges7 bronze badges
532 silver badges7 bronze badges
add a comment |
add a comment |
As mentioned before, JavaScript allows lookbehinds now. In older browsers you still need a workaround.
I bet my head there is no way to find a regex without lookbehind that delivers the result exactly. All you can do is working with groups. Suppose you have a regex (?<!Before)Wanted, where Wanted is the regex you want to match and Before is the regex that counts out what should not precede the match. The best you can do is negate the regex Before and use the regex NotBefore(Wanted). The desired result is the first group $1.
In your case Before=[abcdefg] which is easy to negate NotBefore=[^abcdefg]. So the regex would be [^abcdefg](m). If you need the position of Wanted, you must group NotBefore too, so that the desired result is the second group.
If matches of the Before pattern have a fixed length n, that is, if the pattern contains no repetitive tokens, you can avoid negating the Before pattern and use the regular expression (?!Before).n(Wanted), but still have to use the first group or use the regular expression (?!Before)(.n)(Wanted) and use the second group. In this example, the pattern Before actually has a fixed length, namely 1, so use the regex (?![abcdefg]).(m) or (?![abcdefg])(.)(m). If you are interested in all matches, add the g flag, see my code snippet:
function TestSORegEx()
var s = "Donald Trump doesn't like jam, but Homer Simpson does.";
var reg = /(?![abcdefg])(.1)(m)/gm;
var out = "Matches and groups of the regex " +
"/(?![abcdefg])(.1)(m)/gm in ns = "" + s + """;
var match = reg.exec(s);
while(match)
var start = match.index + match[1].length;
out += "nWhole match: " + match[0] + ", starts at: " + match.index
+ ". Desired match: " + match[2] + ", starts at: " + start + ".";
match = reg.exec(s);
out += "nResulting string after statement s.replace(reg, "$1*$2*")n"
+ s.replace(reg, "$1*$2*");
alert(out);
add a comment |
As mentioned before, JavaScript allows lookbehinds now. In older browsers you still need a workaround.
I bet my head there is no way to find a regex without lookbehind that delivers the result exactly. All you can do is working with groups. Suppose you have a regex (?<!Before)Wanted, where Wanted is the regex you want to match and Before is the regex that counts out what should not precede the match. The best you can do is negate the regex Before and use the regex NotBefore(Wanted). The desired result is the first group $1.
In your case Before=[abcdefg] which is easy to negate NotBefore=[^abcdefg]. So the regex would be [^abcdefg](m). If you need the position of Wanted, you must group NotBefore too, so that the desired result is the second group.
If matches of the Before pattern have a fixed length n, that is, if the pattern contains no repetitive tokens, you can avoid negating the Before pattern and use the regular expression (?!Before).n(Wanted), but still have to use the first group or use the regular expression (?!Before)(.n)(Wanted) and use the second group. In this example, the pattern Before actually has a fixed length, namely 1, so use the regex (?![abcdefg]).(m) or (?![abcdefg])(.)(m). If you are interested in all matches, add the g flag, see my code snippet:
function TestSORegEx()
var s = "Donald Trump doesn't like jam, but Homer Simpson does.";
var reg = /(?![abcdefg])(.1)(m)/gm;
var out = "Matches and groups of the regex " +
"/(?![abcdefg])(.1)(m)/gm in ns = "" + s + """;
var match = reg.exec(s);
while(match)
var start = match.index + match[1].length;
out += "nWhole match: " + match[0] + ", starts at: " + match.index
+ ". Desired match: " + match[2] + ", starts at: " + start + ".";
match = reg.exec(s);
out += "nResulting string after statement s.replace(reg, "$1*$2*")n"
+ s.replace(reg, "$1*$2*");
alert(out);
add a comment |
As mentioned before, JavaScript allows lookbehinds now. In older browsers you still need a workaround.
I bet my head there is no way to find a regex without lookbehind that delivers the result exactly. All you can do is working with groups. Suppose you have a regex (?<!Before)Wanted, where Wanted is the regex you want to match and Before is the regex that counts out what should not precede the match. The best you can do is negate the regex Before and use the regex NotBefore(Wanted). The desired result is the first group $1.
In your case Before=[abcdefg] which is easy to negate NotBefore=[^abcdefg]. So the regex would be [^abcdefg](m). If you need the position of Wanted, you must group NotBefore too, so that the desired result is the second group.
If matches of the Before pattern have a fixed length n, that is, if the pattern contains no repetitive tokens, you can avoid negating the Before pattern and use the regular expression (?!Before).n(Wanted), but still have to use the first group or use the regular expression (?!Before)(.n)(Wanted) and use the second group. In this example, the pattern Before actually has a fixed length, namely 1, so use the regex (?![abcdefg]).(m) or (?![abcdefg])(.)(m). If you are interested in all matches, add the g flag, see my code snippet:
function TestSORegEx()
var s = "Donald Trump doesn't like jam, but Homer Simpson does.";
var reg = /(?![abcdefg])(.1)(m)/gm;
var out = "Matches and groups of the regex " +
"/(?![abcdefg])(.1)(m)/gm in ns = "" + s + """;
var match = reg.exec(s);
while(match)
var start = match.index + match[1].length;
out += "nWhole match: " + match[0] + ", starts at: " + match.index
+ ". Desired match: " + match[2] + ", starts at: " + start + ".";
match = reg.exec(s);
out += "nResulting string after statement s.replace(reg, "$1*$2*")n"
+ s.replace(reg, "$1*$2*");
alert(out);
As mentioned before, JavaScript allows lookbehinds now. In older browsers you still need a workaround.
I bet my head there is no way to find a regex without lookbehind that delivers the result exactly. All you can do is working with groups. Suppose you have a regex (?<!Before)Wanted, where Wanted is the regex you want to match and Before is the regex that counts out what should not precede the match. The best you can do is negate the regex Before and use the regex NotBefore(Wanted). The desired result is the first group $1.
In your case Before=[abcdefg] which is easy to negate NotBefore=[^abcdefg]. So the regex would be [^abcdefg](m). If you need the position of Wanted, you must group NotBefore too, so that the desired result is the second group.
If matches of the Before pattern have a fixed length n, that is, if the pattern contains no repetitive tokens, you can avoid negating the Before pattern and use the regular expression (?!Before).n(Wanted), but still have to use the first group or use the regular expression (?!Before)(.n)(Wanted) and use the second group. In this example, the pattern Before actually has a fixed length, namely 1, so use the regex (?![abcdefg]).(m) or (?![abcdefg])(.)(m). If you are interested in all matches, add the g flag, see my code snippet:
function TestSORegEx()
var s = "Donald Trump doesn't like jam, but Homer Simpson does.";
var reg = /(?![abcdefg])(.1)(m)/gm;
var out = "Matches and groups of the regex " +
"/(?![abcdefg])(.1)(m)/gm in ns = "" + s + """;
var match = reg.exec(s);
while(match)
var start = match.index + match[1].length;
out += "nWhole match: " + match[0] + ", starts at: " + match.index
+ ". Desired match: " + match[2] + ", starts at: " + start + ".";
match = reg.exec(s);
out += "nResulting string after statement s.replace(reg, "$1*$2*")n"
+ s.replace(reg, "$1*$2*");
alert(out);
edited Jul 8 at 8:25
answered Jul 7 at 12:51
Dietrich BaumgartenDietrich Baumgarten
211 silver badge3 bronze badges
211 silver badge3 bronze badges
add a comment |
add a comment |
/(?![abcdefg])[^abcdefg]m/gi
yes this is a trick.
5
The check(?![abcdefg])is totally redundant, since[^abcdefg]already does its job to prevent those character from matching.
– nhahtdh
Jan 15 '15 at 6:33
2
This will not match an 'm' with no preceding characters.
– Andrew Ensley
Apr 20 '15 at 15:27
add a comment |
/(?![abcdefg])[^abcdefg]m/gi
yes this is a trick.
5
The check(?![abcdefg])is totally redundant, since[^abcdefg]already does its job to prevent those character from matching.
– nhahtdh
Jan 15 '15 at 6:33
2
This will not match an 'm' with no preceding characters.
– Andrew Ensley
Apr 20 '15 at 15:27
add a comment |
/(?![abcdefg])[^abcdefg]m/gi
yes this is a trick.
/(?![abcdefg])[^abcdefg]m/gi
yes this is a trick.
answered Nov 4 '13 at 21:24
TechsinTechsin
3842 silver badges16 bronze badges
3842 silver badges16 bronze badges
5
The check(?![abcdefg])is totally redundant, since[^abcdefg]already does its job to prevent those character from matching.
– nhahtdh
Jan 15 '15 at 6:33
2
This will not match an 'm' with no preceding characters.
– Andrew Ensley
Apr 20 '15 at 15:27
add a comment |
5
The check(?![abcdefg])is totally redundant, since[^abcdefg]already does its job to prevent those character from matching.
– nhahtdh
Jan 15 '15 at 6:33
2
This will not match an 'm' with no preceding characters.
– Andrew Ensley
Apr 20 '15 at 15:27
5
5
The check
(?![abcdefg]) is totally redundant, since [^abcdefg] already does its job to prevent those character from matching.– nhahtdh
Jan 15 '15 at 6:33
The check
(?![abcdefg]) is totally redundant, since [^abcdefg] already does its job to prevent those character from matching.– nhahtdh
Jan 15 '15 at 6:33
2
2
This will not match an 'm' with no preceding characters.
– Andrew Ensley
Apr 20 '15 at 15:27
This will not match an 'm' with no preceding characters.
– Andrew Ensley
Apr 20 '15 at 15:27
add a comment |
This might help, depending on the context:
This matches the m in jim but not jam:
"jim jam".replace(/[a-g]m/g, "").match(/m/g)
This works purely for matching, but then I don't have the original string for any sort of manipulation. Very close.
– Andrew Ensley
Apr 13 '16 at 14:21
add a comment |
This might help, depending on the context:
This matches the m in jim but not jam:
"jim jam".replace(/[a-g]m/g, "").match(/m/g)
This works purely for matching, but then I don't have the original string for any sort of manipulation. Very close.
– Andrew Ensley
Apr 13 '16 at 14:21
add a comment |
This might help, depending on the context:
This matches the m in jim but not jam:
"jim jam".replace(/[a-g]m/g, "").match(/m/g)
This might help, depending on the context:
This matches the m in jim but not jam:
"jim jam".replace(/[a-g]m/g, "").match(/m/g)
answered Apr 12 '16 at 0:34
Curtis YallopCurtis Yallop
4,5563 gold badges26 silver badges25 bronze badges
4,5563 gold badges26 silver badges25 bronze badges
This works purely for matching, but then I don't have the original string for any sort of manipulation. Very close.
– Andrew Ensley
Apr 13 '16 at 14:21
add a comment |
This works purely for matching, but then I don't have the original string for any sort of manipulation. Very close.
– Andrew Ensley
Apr 13 '16 at 14:21
This works purely for matching, but then I don't have the original string for any sort of manipulation. Very close.
– Andrew Ensley
Apr 13 '16 at 14:21
This works purely for matching, but then I don't have the original string for any sort of manipulation. Very close.
– Andrew Ensley
Apr 13 '16 at 14:21
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f641407%2fjavascript-negative-lookbehind-equivalent%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Consider posting the regex as it would look with a negative lookbehind; that may make it easier to respond.
– Daniel LeCheminant
Mar 13 '09 at 3:53