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;








126















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'










share|improve this question


























  • 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

















126















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'










share|improve this question


























  • 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













126












126








126


30






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'










share|improve this question
















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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

















  • 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












13 Answers
13






active

oldest

votes


















36














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


  • ❌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





share|improve this answer






















  • 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


















79














As Javascript supports negative lookahead, one way to do it is:



  1. reverse the input string


  2. match with a reversed regex


  3. 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: Ø





share|improve this answer






















  • 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 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












  • I tried that and it shows me a pattern error.

    – Thielicious
    Sep 2 '18 at 15:25


















55














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.






share|improve this answer






















  • 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



















41














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.






share|improve this answer






















  • 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


















33














Use



newString = string.replace(/([abcdefg])?m/, function($0,$1) return $1?$0:'m';);





share|improve this answer




















  • 9





    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






  • 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 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


















9














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.






share|improve this answer






















  • 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


















1














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. :)






share|improve this answer


































    0














    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.






    share|improve this answer

























    • 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



















    0














    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.






    share|improve this answer
































      0














      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.






      share|improve this answer
































        0














        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);






        share|improve this answer


































          -1














          /(?![abcdefg])[^abcdefg]m/gi
          yes this is a trick.






          share|improve this answer




















          • 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


















          -1














          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)





          share|improve this answer

























          • 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













          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
          );



          );













          draft saved

          draft discarded


















          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









          36














          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


          • ❌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





          share|improve this answer






















          • 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















          36














          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


          • ❌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





          share|improve this answer






















          • 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













          36












          36








          36







          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


          • ❌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





          share|improve this answer















          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


          • ❌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"
          );






          share|improve this answer














          share|improve this answer



          share|improve this answer








          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












          • 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













          79














          As Javascript supports negative lookahead, one way to do it is:



          1. reverse the input string


          2. match with a reversed regex


          3. 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: Ø





          share|improve this answer






















          • 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 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












          • I tried that and it shows me a pattern error.

            – Thielicious
            Sep 2 '18 at 15:25















          79














          As Javascript supports negative lookahead, one way to do it is:



          1. reverse the input string


          2. match with a reversed regex


          3. 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: Ø





          share|improve this answer






















          • 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 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












          • I tried that and it shows me a pattern error.

            – Thielicious
            Sep 2 '18 at 15:25













          79












          79








          79







          As Javascript supports negative lookahead, one way to do it is:



          1. reverse the input string


          2. match with a reversed regex


          3. 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: Ø





          share|improve this answer















          As Javascript supports negative lookahead, one way to do it is:



          1. reverse the input string


          2. match with a reversed regex


          3. 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: Ø






          share|improve this answer














          share|improve this answer



          share|improve this answer








          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 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












          • I tried that and it shows me a pattern error.

            – Thielicious
            Sep 2 '18 at 15:25












          • 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 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












          • 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











          55














          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.






          share|improve this answer






















          • 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
















          55














          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.






          share|improve this answer






















          • 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














          55












          55








          55







          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.






          share|improve this answer















          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.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          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













          • 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












          41














          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.






          share|improve this answer






















          • 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















          41














          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.






          share|improve this answer






















          • 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













          41












          41








          41







          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.






          share|improve this answer















          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.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          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












          • 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











          33














          Use



          newString = string.replace(/([abcdefg])?m/, function($0,$1) return $1?$0:'m';);





          share|improve this answer




















          • 9





            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






          • 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 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















          33














          Use



          newString = string.replace(/([abcdefg])?m/, function($0,$1) return $1?$0:'m';);





          share|improve this answer




















          • 9





            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






          • 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 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













          33












          33








          33







          Use



          newString = string.replace(/([abcdefg])?m/, function($0,$1) return $1?$0:'m';);





          share|improve this answer













          Use



          newString = string.replace(/([abcdefg])?m/, function($0,$1) return $1?$0:'m';);






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Mar 13 '09 at 4:11









          MijojaMijoja

          6536 silver badges7 bronze badges




          6536 silver badges7 bronze badges










          • 9





            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






          • 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 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












          • 9





            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






          • 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 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







          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











          9














          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.






          share|improve this answer






















          • 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















          9














          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.






          share|improve this answer






















          • 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













          9












          9








          9







          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.






          share|improve this answer















          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.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          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












          • 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











          1














          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. :)






          share|improve this answer































            1














            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. :)






            share|improve this answer





























              1












              1








              1







              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. :)






              share|improve this answer















              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. :)







              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Apr 19 '15 at 8:42

























              answered Apr 19 '15 at 7:06









              Homer SimpsonHomer Simpson

              135 bronze badges




              135 bronze badges
























                  0














                  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.






                  share|improve this answer

























                  • 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
















                  0














                  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.






                  share|improve this answer

























                  • 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














                  0












                  0








                  0







                  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.






                  share|improve this answer













                  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.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  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/) 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

















                  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












                  0














                  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.






                  share|improve this answer





























                    0














                    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.






                    share|improve this answer



























                      0












                      0








                      0







                      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.






                      share|improve this answer













                      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.







                      share|improve this answer












                      share|improve this answer



                      share|improve this answer










                      answered Feb 16 '18 at 13:28









                      TraxoTraxo

                      7,6002 gold badges30 silver badges56 bronze badges




                      7,6002 gold badges30 silver badges56 bronze badges
























                          0














                          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.






                          share|improve this answer





























                            0














                            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.






                            share|improve this answer



























                              0












                              0








                              0







                              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.






                              share|improve this answer













                              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.







                              share|improve this answer












                              share|improve this answer



                              share|improve this answer










                              answered Apr 1 at 19:43









                              Fishrock123Fishrock123

                              532 silver badges7 bronze badges




                              532 silver badges7 bronze badges
























                                  0














                                  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);






                                  share|improve this answer































                                    0














                                    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);






                                    share|improve this answer





























                                      0












                                      0








                                      0







                                      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);






                                      share|improve this answer















                                      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);







                                      share|improve this answer














                                      share|improve this answer



                                      share|improve this answer








                                      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
























                                          -1














                                          /(?![abcdefg])[^abcdefg]m/gi
                                          yes this is a trick.






                                          share|improve this answer




















                                          • 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















                                          -1














                                          /(?![abcdefg])[^abcdefg]m/gi
                                          yes this is a trick.






                                          share|improve this answer




















                                          • 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













                                          -1












                                          -1








                                          -1







                                          /(?![abcdefg])[^abcdefg]m/gi
                                          yes this is a trick.






                                          share|improve this answer













                                          /(?![abcdefg])[^abcdefg]m/gi
                                          yes this is a trick.







                                          share|improve this answer












                                          share|improve this answer



                                          share|improve this answer










                                          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












                                          • 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











                                          -1














                                          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)





                                          share|improve this answer

























                                          • 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















                                          -1














                                          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)





                                          share|improve this answer

























                                          • 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













                                          -1












                                          -1








                                          -1







                                          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)





                                          share|improve this answer













                                          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)






                                          share|improve this answer












                                          share|improve this answer



                                          share|improve this answer










                                          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

















                                          • 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

















                                          draft saved

                                          draft discarded
















































                                          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.




                                          draft saved


                                          draft discarded














                                          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





















































                                          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







                                          Popular posts from this blog

                                          SQL error code 1064 with creating Laravel foreign keysForeign key constraints: When to use ON UPDATE and ON DELETEDropping column with foreign key Laravel error: General error: 1025 Error on renameLaravel SQL Can't create tableLaravel Migration foreign key errorLaravel php artisan migrate:refresh giving a syntax errorSQLSTATE[42S01]: Base table or view already exists or Base table or view already exists: 1050 Tableerror in migrating laravel file to xampp serverSyntax error or access violation: 1064:syntax to use near 'unsigned not null, modelName varchar(191) not null, title varchar(191) not nLaravel cannot create new table field in mysqlLaravel 5.7:Last migration creates table but is not registered in the migration table

                                          용인 삼성생명 블루밍스 목차 통계 역대 감독 선수단 응원단 경기장 같이 보기 외부 링크 둘러보기 메뉴samsungblueminx.comeh선수 명단용인 삼성생명 블루밍스용인 삼성생명 블루밍스ehsamsungblueminx.comeheheheh

                                          155 수학 과학 기타 둘러보기 메뉴eh추가해eh문서를 완성해