Why does a RegExp with global flag give wrong results?












226















What is the problem with this regular expression when I use the global flag and the case insensitive flag? Query is a user generated input. The result should be [true, true].



var query = 'Foo B';
var re = new RegExp(query, 'gi');
var result = ;
result.push(re.test('Foo Bar'));
result.push(re.test('Foo Bar'));
// result will be [true, false]







var reg = /^a$/g;
for(i = 0; i++ < 10;)
console.log(reg.test("a"));












share|improve this question




















  • 47





    Welcome to one of the many traps of RegExp in JavaScript. It has one of the worst interfaces to regex processing I've ever met, full of weird side-effects and obscure caveats. Most of the common tasks you typically want to do with regex are difficult to spell right.

    – bobince
    Oct 5 '09 at 16:07











  • XRegExp looks like a good alternative. xregexp.com

    – about
    Oct 5 '09 at 18:49











  • See answer here as well: stackoverflow.com/questions/604860/…

    – Prestaul
    Aug 28 '14 at 18:40











  • One solution, if you can get away with it, is to use the regex literal directly instead of saving it to re.

    – thdoan
    Oct 10 '18 at 17:26
















226















What is the problem with this regular expression when I use the global flag and the case insensitive flag? Query is a user generated input. The result should be [true, true].



var query = 'Foo B';
var re = new RegExp(query, 'gi');
var result = ;
result.push(re.test('Foo Bar'));
result.push(re.test('Foo Bar'));
// result will be [true, false]







var reg = /^a$/g;
for(i = 0; i++ < 10;)
console.log(reg.test("a"));












share|improve this question




















  • 47





    Welcome to one of the many traps of RegExp in JavaScript. It has one of the worst interfaces to regex processing I've ever met, full of weird side-effects and obscure caveats. Most of the common tasks you typically want to do with regex are difficult to spell right.

    – bobince
    Oct 5 '09 at 16:07











  • XRegExp looks like a good alternative. xregexp.com

    – about
    Oct 5 '09 at 18:49











  • See answer here as well: stackoverflow.com/questions/604860/…

    – Prestaul
    Aug 28 '14 at 18:40











  • One solution, if you can get away with it, is to use the regex literal directly instead of saving it to re.

    – thdoan
    Oct 10 '18 at 17:26














226












226








226


80






What is the problem with this regular expression when I use the global flag and the case insensitive flag? Query is a user generated input. The result should be [true, true].



var query = 'Foo B';
var re = new RegExp(query, 'gi');
var result = ;
result.push(re.test('Foo Bar'));
result.push(re.test('Foo Bar'));
// result will be [true, false]







var reg = /^a$/g;
for(i = 0; i++ < 10;)
console.log(reg.test("a"));












share|improve this question
















What is the problem with this regular expression when I use the global flag and the case insensitive flag? Query is a user generated input. The result should be [true, true].



var query = 'Foo B';
var re = new RegExp(query, 'gi');
var result = ;
result.push(re.test('Foo Bar'));
result.push(re.test('Foo Bar'));
// result will be [true, false]







var reg = /^a$/g;
for(i = 0; i++ < 10;)
console.log(reg.test("a"));








var reg = /^a$/g;
for(i = 0; i++ < 10;)
console.log(reg.test("a"));





var reg = /^a$/g;
for(i = 0; i++ < 10;)
console.log(reg.test("a"));






javascript regex






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jun 9 '17 at 8:55









zb226

5,71132851




5,71132851










asked Oct 5 '09 at 15:32









aboutabout

1,33731012




1,33731012








  • 47





    Welcome to one of the many traps of RegExp in JavaScript. It has one of the worst interfaces to regex processing I've ever met, full of weird side-effects and obscure caveats. Most of the common tasks you typically want to do with regex are difficult to spell right.

    – bobince
    Oct 5 '09 at 16:07











  • XRegExp looks like a good alternative. xregexp.com

    – about
    Oct 5 '09 at 18:49











  • See answer here as well: stackoverflow.com/questions/604860/…

    – Prestaul
    Aug 28 '14 at 18:40











  • One solution, if you can get away with it, is to use the regex literal directly instead of saving it to re.

    – thdoan
    Oct 10 '18 at 17:26














  • 47





    Welcome to one of the many traps of RegExp in JavaScript. It has one of the worst interfaces to regex processing I've ever met, full of weird side-effects and obscure caveats. Most of the common tasks you typically want to do with regex are difficult to spell right.

    – bobince
    Oct 5 '09 at 16:07











  • XRegExp looks like a good alternative. xregexp.com

    – about
    Oct 5 '09 at 18:49











  • See answer here as well: stackoverflow.com/questions/604860/…

    – Prestaul
    Aug 28 '14 at 18:40











  • One solution, if you can get away with it, is to use the regex literal directly instead of saving it to re.

    – thdoan
    Oct 10 '18 at 17:26








47




47





Welcome to one of the many traps of RegExp in JavaScript. It has one of the worst interfaces to regex processing I've ever met, full of weird side-effects and obscure caveats. Most of the common tasks you typically want to do with regex are difficult to spell right.

– bobince
Oct 5 '09 at 16:07





Welcome to one of the many traps of RegExp in JavaScript. It has one of the worst interfaces to regex processing I've ever met, full of weird side-effects and obscure caveats. Most of the common tasks you typically want to do with regex are difficult to spell right.

– bobince
Oct 5 '09 at 16:07













XRegExp looks like a good alternative. xregexp.com

– about
Oct 5 '09 at 18:49





XRegExp looks like a good alternative. xregexp.com

– about
Oct 5 '09 at 18:49













See answer here as well: stackoverflow.com/questions/604860/…

– Prestaul
Aug 28 '14 at 18:40





See answer here as well: stackoverflow.com/questions/604860/…

– Prestaul
Aug 28 '14 at 18:40













One solution, if you can get away with it, is to use the regex literal directly instead of saving it to re.

– thdoan
Oct 10 '18 at 17:26





One solution, if you can get away with it, is to use the regex literal directly instead of saving it to re.

– thdoan
Oct 10 '18 at 17:26












6 Answers
6






active

oldest

votes


















286














The RegExp object keeps track of the lastIndex where a match occurred, so on subsequent matches it will start from the last used index, instead of 0. Take a look:



var query = 'Foo B';
var re = new RegExp(query, 'gi');
var result = ;
result.push(re.test('Foo Bar'));

alert(re.lastIndex);

result.push(re.test('Foo Bar'));


If you don't want to manually reset lastIndex to 0 after every test, just remove the g flag.



Here's the algorithm that the specs dictate (section 15.10.6.2):




RegExp.prototype.exec(string)



Performs
a regular expression match of string
against the regular expression and
returns an Array object containing the
results of the match, or null if the
string did not match The string
ToString(string) is searched for an
occurrence of the regular expression
pattern as follows:




  1. Let S be the value of ToString(string).

  2. Let length be the length of S.

  3. Let lastIndex be the value of the lastIndex property.

  4. Let i be the value of ToInteger(lastIndex).

  5. If the global property is false, let i = 0.

  6. If I < 0 or I > length then set lastIndex to 0 and return null.

  7. Call [[Match]], giving it the arguments S and i. If [[Match]]
    returned failure, go to step 8;
    otherwise let r be its State result
    and go to step 10.

  8. Let i = i+1.

  9. Go to step 6.

  10. Let e be r's endIndex value.

  11. If the global property is true, set lastIndex to e.

  12. Let n be the length of r's captures array. (This is the same
    value as 15.10.2.1's
    NCapturingParens.)

  13. Return a new array with the following properties:


    • The index
      property is set to the position of the
      matched substring within the complete
      string S.

    • The input property is set
      to S.

    • The length property is set to
      n + 1.

    • The 0 property is set to the
      matched substring (i.e. the portion of
      S between offset i inclusive and
      offset e exclusive).

    • For each
      integer i such that I > 0 and I ≤ n,
      set the property named ToString(i) to
      the ith element of r's captures array.









share|improve this answer





















  • 60





    This is like Hitchhiker's Guide to the Galaxy API design here. "That pitfall that you fell in has been perfectly documented in the spec for several years, if you had only bothered to check"

    – Retsam
    Aug 22 '13 at 19:54






  • 4





    Firefox's sticky flag doesn't do what you imply at all. Rather, it acts as if there were a ^ at the start of the regular expression, EXCEPT that this ^ matches the current string position (lastIndex) rather than the start of the string. You're effectively testing if the regex matches "right here" instead of "anywhere after lastIndex". See the link you provided!

    – Doin
    Jan 14 '14 at 12:15











  • The opening statement of this answer is just not accurate. You highlighted step 3 of the spec which says nothing. The actual influence of lastIndex is in steps 5, 6 and 11. Your opening statement is only true IF THE GLOBAL FLAG IS SET.

    – Prestaul
    Aug 28 '14 at 18:38













  • @Prestaul yes, you're right that it doesn't mention the global flag. It was probably (can't remember what I thought back then) implicit due to the way the question is framed. Feel free to edit the answer or delete it and link to your answer. Also, let me reassure you that you're better than me. Enjoy!

    – Ionuț G. Stan
    Aug 29 '14 at 0:45











  • @IonuțG.Stan, sorry if my previous comment seemed attacky, that was not my intent. I can't edit it at this point, but I wasn't trying to shout, just to draw attention to the essential point of my comment. My bad!

    – Prestaul
    Aug 29 '14 at 22:11





















62














You are using a single RegExp object and executing it multiple times. On each successive execution it continues on from the last match index.



You need to "reset" the regex to start from the beginning before each execution:



result.push(re.test('Foo Bar'));
re.lastIndex = 0;
result.push(re.test('Foo Bar'));
// result is now [true, true]


Having said that it may be more readable to create a new RegExp object each time (overhead is minimal as the RegExp is cached anyway):



result.push((/Foo B/gi).test(stringA));
result.push((/Foo B/gi).test(stringB));





share|improve this answer































    34














    RegExp.prototype.test updates the regular expressions' lastIndex property so that each test will start where the last one stopped. I'd suggest using String.prototype.match since it doesn't update the lastIndex property:



    !!'Foo Bar'.match(re); // -> true
    !!'Foo Bar'.match(re); // -> true


    Note: !! converts it to a boolean and then inverts the boolean so it reflects the result.



    Alternatively, you could just reset the lastIndex property:



    result.push(re.test('Foo Bar'));
    re.lastIndex = 0;
    result.push(re.test('Foo Bar'));





    share|improve this answer































      9














      Removing global g flag will fix your problem.



      var re = new RegExp(query, 'gi');


      Should be



      var re = new RegExp(query, 'i');





      share|improve this answer

































        0














        Using the /g flag tells it to continue searching after a hit.



        If the match succeeds, the exec() method returns an array and updates properties of the regular expression object.



        Before your first search:



        myRegex.lastIndex
        //is 0


        After the first search



        myRegex.lastIndex
        //is 8


        Remove the g and it exits the search after each call to exec().






        share|improve this answer































          0














          I had the function:



          function parseDevName(name) {
          var re = /^([^-]+)-([^-]+)-([^-]+)$/g;
          var match = re.exec(name);
          return match.slice(1,4);
          }

          var rv = parseDevName("BR-H-01");
          rv = parseDevName("BR-H-01");


          The first call works.
          The second call doesn't. The slice operation complains about a null value. I assume this is because of the re.lastIndex. This is strange because I would expect a new RegExp to be allocated each time the function is called and not shared across multiple invocations of my function.



          When I changed it to:



          var re = new RegExp('^([^-]+)-([^-]+)-([^-]+)$', 'g');


          Then I don't get the lastIndex holdover effect. It works as I would expect it to.






          share|improve this answer























            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%2f1520800%2fwhy-does-a-regexp-with-global-flag-give-wrong-results%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            6 Answers
            6






            active

            oldest

            votes








            6 Answers
            6






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            286














            The RegExp object keeps track of the lastIndex where a match occurred, so on subsequent matches it will start from the last used index, instead of 0. Take a look:



            var query = 'Foo B';
            var re = new RegExp(query, 'gi');
            var result = ;
            result.push(re.test('Foo Bar'));

            alert(re.lastIndex);

            result.push(re.test('Foo Bar'));


            If you don't want to manually reset lastIndex to 0 after every test, just remove the g flag.



            Here's the algorithm that the specs dictate (section 15.10.6.2):




            RegExp.prototype.exec(string)



            Performs
            a regular expression match of string
            against the regular expression and
            returns an Array object containing the
            results of the match, or null if the
            string did not match The string
            ToString(string) is searched for an
            occurrence of the regular expression
            pattern as follows:




            1. Let S be the value of ToString(string).

            2. Let length be the length of S.

            3. Let lastIndex be the value of the lastIndex property.

            4. Let i be the value of ToInteger(lastIndex).

            5. If the global property is false, let i = 0.

            6. If I < 0 or I > length then set lastIndex to 0 and return null.

            7. Call [[Match]], giving it the arguments S and i. If [[Match]]
              returned failure, go to step 8;
              otherwise let r be its State result
              and go to step 10.

            8. Let i = i+1.

            9. Go to step 6.

            10. Let e be r's endIndex value.

            11. If the global property is true, set lastIndex to e.

            12. Let n be the length of r's captures array. (This is the same
              value as 15.10.2.1's
              NCapturingParens.)

            13. Return a new array with the following properties:


              • The index
                property is set to the position of the
                matched substring within the complete
                string S.

              • The input property is set
                to S.

              • The length property is set to
                n + 1.

              • The 0 property is set to the
                matched substring (i.e. the portion of
                S between offset i inclusive and
                offset e exclusive).

              • For each
                integer i such that I > 0 and I ≤ n,
                set the property named ToString(i) to
                the ith element of r's captures array.









            share|improve this answer





















            • 60





              This is like Hitchhiker's Guide to the Galaxy API design here. "That pitfall that you fell in has been perfectly documented in the spec for several years, if you had only bothered to check"

              – Retsam
              Aug 22 '13 at 19:54






            • 4





              Firefox's sticky flag doesn't do what you imply at all. Rather, it acts as if there were a ^ at the start of the regular expression, EXCEPT that this ^ matches the current string position (lastIndex) rather than the start of the string. You're effectively testing if the regex matches "right here" instead of "anywhere after lastIndex". See the link you provided!

              – Doin
              Jan 14 '14 at 12:15











            • The opening statement of this answer is just not accurate. You highlighted step 3 of the spec which says nothing. The actual influence of lastIndex is in steps 5, 6 and 11. Your opening statement is only true IF THE GLOBAL FLAG IS SET.

              – Prestaul
              Aug 28 '14 at 18:38













            • @Prestaul yes, you're right that it doesn't mention the global flag. It was probably (can't remember what I thought back then) implicit due to the way the question is framed. Feel free to edit the answer or delete it and link to your answer. Also, let me reassure you that you're better than me. Enjoy!

              – Ionuț G. Stan
              Aug 29 '14 at 0:45











            • @IonuțG.Stan, sorry if my previous comment seemed attacky, that was not my intent. I can't edit it at this point, but I wasn't trying to shout, just to draw attention to the essential point of my comment. My bad!

              – Prestaul
              Aug 29 '14 at 22:11


















            286














            The RegExp object keeps track of the lastIndex where a match occurred, so on subsequent matches it will start from the last used index, instead of 0. Take a look:



            var query = 'Foo B';
            var re = new RegExp(query, 'gi');
            var result = ;
            result.push(re.test('Foo Bar'));

            alert(re.lastIndex);

            result.push(re.test('Foo Bar'));


            If you don't want to manually reset lastIndex to 0 after every test, just remove the g flag.



            Here's the algorithm that the specs dictate (section 15.10.6.2):




            RegExp.prototype.exec(string)



            Performs
            a regular expression match of string
            against the regular expression and
            returns an Array object containing the
            results of the match, or null if the
            string did not match The string
            ToString(string) is searched for an
            occurrence of the regular expression
            pattern as follows:




            1. Let S be the value of ToString(string).

            2. Let length be the length of S.

            3. Let lastIndex be the value of the lastIndex property.

            4. Let i be the value of ToInteger(lastIndex).

            5. If the global property is false, let i = 0.

            6. If I < 0 or I > length then set lastIndex to 0 and return null.

            7. Call [[Match]], giving it the arguments S and i. If [[Match]]
              returned failure, go to step 8;
              otherwise let r be its State result
              and go to step 10.

            8. Let i = i+1.

            9. Go to step 6.

            10. Let e be r's endIndex value.

            11. If the global property is true, set lastIndex to e.

            12. Let n be the length of r's captures array. (This is the same
              value as 15.10.2.1's
              NCapturingParens.)

            13. Return a new array with the following properties:


              • The index
                property is set to the position of the
                matched substring within the complete
                string S.

              • The input property is set
                to S.

              • The length property is set to
                n + 1.

              • The 0 property is set to the
                matched substring (i.e. the portion of
                S between offset i inclusive and
                offset e exclusive).

              • For each
                integer i such that I > 0 and I ≤ n,
                set the property named ToString(i) to
                the ith element of r's captures array.









            share|improve this answer





















            • 60





              This is like Hitchhiker's Guide to the Galaxy API design here. "That pitfall that you fell in has been perfectly documented in the spec for several years, if you had only bothered to check"

              – Retsam
              Aug 22 '13 at 19:54






            • 4





              Firefox's sticky flag doesn't do what you imply at all. Rather, it acts as if there were a ^ at the start of the regular expression, EXCEPT that this ^ matches the current string position (lastIndex) rather than the start of the string. You're effectively testing if the regex matches "right here" instead of "anywhere after lastIndex". See the link you provided!

              – Doin
              Jan 14 '14 at 12:15











            • The opening statement of this answer is just not accurate. You highlighted step 3 of the spec which says nothing. The actual influence of lastIndex is in steps 5, 6 and 11. Your opening statement is only true IF THE GLOBAL FLAG IS SET.

              – Prestaul
              Aug 28 '14 at 18:38













            • @Prestaul yes, you're right that it doesn't mention the global flag. It was probably (can't remember what I thought back then) implicit due to the way the question is framed. Feel free to edit the answer or delete it and link to your answer. Also, let me reassure you that you're better than me. Enjoy!

              – Ionuț G. Stan
              Aug 29 '14 at 0:45











            • @IonuțG.Stan, sorry if my previous comment seemed attacky, that was not my intent. I can't edit it at this point, but I wasn't trying to shout, just to draw attention to the essential point of my comment. My bad!

              – Prestaul
              Aug 29 '14 at 22:11
















            286












            286








            286







            The RegExp object keeps track of the lastIndex where a match occurred, so on subsequent matches it will start from the last used index, instead of 0. Take a look:



            var query = 'Foo B';
            var re = new RegExp(query, 'gi');
            var result = ;
            result.push(re.test('Foo Bar'));

            alert(re.lastIndex);

            result.push(re.test('Foo Bar'));


            If you don't want to manually reset lastIndex to 0 after every test, just remove the g flag.



            Here's the algorithm that the specs dictate (section 15.10.6.2):




            RegExp.prototype.exec(string)



            Performs
            a regular expression match of string
            against the regular expression and
            returns an Array object containing the
            results of the match, or null if the
            string did not match The string
            ToString(string) is searched for an
            occurrence of the regular expression
            pattern as follows:




            1. Let S be the value of ToString(string).

            2. Let length be the length of S.

            3. Let lastIndex be the value of the lastIndex property.

            4. Let i be the value of ToInteger(lastIndex).

            5. If the global property is false, let i = 0.

            6. If I < 0 or I > length then set lastIndex to 0 and return null.

            7. Call [[Match]], giving it the arguments S and i. If [[Match]]
              returned failure, go to step 8;
              otherwise let r be its State result
              and go to step 10.

            8. Let i = i+1.

            9. Go to step 6.

            10. Let e be r's endIndex value.

            11. If the global property is true, set lastIndex to e.

            12. Let n be the length of r's captures array. (This is the same
              value as 15.10.2.1's
              NCapturingParens.)

            13. Return a new array with the following properties:


              • The index
                property is set to the position of the
                matched substring within the complete
                string S.

              • The input property is set
                to S.

              • The length property is set to
                n + 1.

              • The 0 property is set to the
                matched substring (i.e. the portion of
                S between offset i inclusive and
                offset e exclusive).

              • For each
                integer i such that I > 0 and I ≤ n,
                set the property named ToString(i) to
                the ith element of r's captures array.









            share|improve this answer















            The RegExp object keeps track of the lastIndex where a match occurred, so on subsequent matches it will start from the last used index, instead of 0. Take a look:



            var query = 'Foo B';
            var re = new RegExp(query, 'gi');
            var result = ;
            result.push(re.test('Foo Bar'));

            alert(re.lastIndex);

            result.push(re.test('Foo Bar'));


            If you don't want to manually reset lastIndex to 0 after every test, just remove the g flag.



            Here's the algorithm that the specs dictate (section 15.10.6.2):




            RegExp.prototype.exec(string)



            Performs
            a regular expression match of string
            against the regular expression and
            returns an Array object containing the
            results of the match, or null if the
            string did not match The string
            ToString(string) is searched for an
            occurrence of the regular expression
            pattern as follows:




            1. Let S be the value of ToString(string).

            2. Let length be the length of S.

            3. Let lastIndex be the value of the lastIndex property.

            4. Let i be the value of ToInteger(lastIndex).

            5. If the global property is false, let i = 0.

            6. If I < 0 or I > length then set lastIndex to 0 and return null.

            7. Call [[Match]], giving it the arguments S and i. If [[Match]]
              returned failure, go to step 8;
              otherwise let r be its State result
              and go to step 10.

            8. Let i = i+1.

            9. Go to step 6.

            10. Let e be r's endIndex value.

            11. If the global property is true, set lastIndex to e.

            12. Let n be the length of r's captures array. (This is the same
              value as 15.10.2.1's
              NCapturingParens.)

            13. Return a new array with the following properties:


              • The index
                property is set to the position of the
                matched substring within the complete
                string S.

              • The input property is set
                to S.

              • The length property is set to
                n + 1.

              • The 0 property is set to the
                matched substring (i.e. the portion of
                S between offset i inclusive and
                offset e exclusive).

              • For each
                integer i such that I > 0 and I ≤ n,
                set the property named ToString(i) to
                the ith element of r's captures array.










            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Apr 20 '15 at 13:48









            Joe White

            56.3k46190304




            56.3k46190304










            answered Oct 5 '09 at 15:42









            Ionuț G. StanIonuț G. Stan

            132k18159188




            132k18159188








            • 60





              This is like Hitchhiker's Guide to the Galaxy API design here. "That pitfall that you fell in has been perfectly documented in the spec for several years, if you had only bothered to check"

              – Retsam
              Aug 22 '13 at 19:54






            • 4





              Firefox's sticky flag doesn't do what you imply at all. Rather, it acts as if there were a ^ at the start of the regular expression, EXCEPT that this ^ matches the current string position (lastIndex) rather than the start of the string. You're effectively testing if the regex matches "right here" instead of "anywhere after lastIndex". See the link you provided!

              – Doin
              Jan 14 '14 at 12:15











            • The opening statement of this answer is just not accurate. You highlighted step 3 of the spec which says nothing. The actual influence of lastIndex is in steps 5, 6 and 11. Your opening statement is only true IF THE GLOBAL FLAG IS SET.

              – Prestaul
              Aug 28 '14 at 18:38













            • @Prestaul yes, you're right that it doesn't mention the global flag. It was probably (can't remember what I thought back then) implicit due to the way the question is framed. Feel free to edit the answer or delete it and link to your answer. Also, let me reassure you that you're better than me. Enjoy!

              – Ionuț G. Stan
              Aug 29 '14 at 0:45











            • @IonuțG.Stan, sorry if my previous comment seemed attacky, that was not my intent. I can't edit it at this point, but I wasn't trying to shout, just to draw attention to the essential point of my comment. My bad!

              – Prestaul
              Aug 29 '14 at 22:11
















            • 60





              This is like Hitchhiker's Guide to the Galaxy API design here. "That pitfall that you fell in has been perfectly documented in the spec for several years, if you had only bothered to check"

              – Retsam
              Aug 22 '13 at 19:54






            • 4





              Firefox's sticky flag doesn't do what you imply at all. Rather, it acts as if there were a ^ at the start of the regular expression, EXCEPT that this ^ matches the current string position (lastIndex) rather than the start of the string. You're effectively testing if the regex matches "right here" instead of "anywhere after lastIndex". See the link you provided!

              – Doin
              Jan 14 '14 at 12:15











            • The opening statement of this answer is just not accurate. You highlighted step 3 of the spec which says nothing. The actual influence of lastIndex is in steps 5, 6 and 11. Your opening statement is only true IF THE GLOBAL FLAG IS SET.

              – Prestaul
              Aug 28 '14 at 18:38













            • @Prestaul yes, you're right that it doesn't mention the global flag. It was probably (can't remember what I thought back then) implicit due to the way the question is framed. Feel free to edit the answer or delete it and link to your answer. Also, let me reassure you that you're better than me. Enjoy!

              – Ionuț G. Stan
              Aug 29 '14 at 0:45











            • @IonuțG.Stan, sorry if my previous comment seemed attacky, that was not my intent. I can't edit it at this point, but I wasn't trying to shout, just to draw attention to the essential point of my comment. My bad!

              – Prestaul
              Aug 29 '14 at 22:11










            60




            60





            This is like Hitchhiker's Guide to the Galaxy API design here. "That pitfall that you fell in has been perfectly documented in the spec for several years, if you had only bothered to check"

            – Retsam
            Aug 22 '13 at 19:54





            This is like Hitchhiker's Guide to the Galaxy API design here. "That pitfall that you fell in has been perfectly documented in the spec for several years, if you had only bothered to check"

            – Retsam
            Aug 22 '13 at 19:54




            4




            4





            Firefox's sticky flag doesn't do what you imply at all. Rather, it acts as if there were a ^ at the start of the regular expression, EXCEPT that this ^ matches the current string position (lastIndex) rather than the start of the string. You're effectively testing if the regex matches "right here" instead of "anywhere after lastIndex". See the link you provided!

            – Doin
            Jan 14 '14 at 12:15





            Firefox's sticky flag doesn't do what you imply at all. Rather, it acts as if there were a ^ at the start of the regular expression, EXCEPT that this ^ matches the current string position (lastIndex) rather than the start of the string. You're effectively testing if the regex matches "right here" instead of "anywhere after lastIndex". See the link you provided!

            – Doin
            Jan 14 '14 at 12:15













            The opening statement of this answer is just not accurate. You highlighted step 3 of the spec which says nothing. The actual influence of lastIndex is in steps 5, 6 and 11. Your opening statement is only true IF THE GLOBAL FLAG IS SET.

            – Prestaul
            Aug 28 '14 at 18:38







            The opening statement of this answer is just not accurate. You highlighted step 3 of the spec which says nothing. The actual influence of lastIndex is in steps 5, 6 and 11. Your opening statement is only true IF THE GLOBAL FLAG IS SET.

            – Prestaul
            Aug 28 '14 at 18:38















            @Prestaul yes, you're right that it doesn't mention the global flag. It was probably (can't remember what I thought back then) implicit due to the way the question is framed. Feel free to edit the answer or delete it and link to your answer. Also, let me reassure you that you're better than me. Enjoy!

            – Ionuț G. Stan
            Aug 29 '14 at 0:45





            @Prestaul yes, you're right that it doesn't mention the global flag. It was probably (can't remember what I thought back then) implicit due to the way the question is framed. Feel free to edit the answer or delete it and link to your answer. Also, let me reassure you that you're better than me. Enjoy!

            – Ionuț G. Stan
            Aug 29 '14 at 0:45













            @IonuțG.Stan, sorry if my previous comment seemed attacky, that was not my intent. I can't edit it at this point, but I wasn't trying to shout, just to draw attention to the essential point of my comment. My bad!

            – Prestaul
            Aug 29 '14 at 22:11







            @IonuțG.Stan, sorry if my previous comment seemed attacky, that was not my intent. I can't edit it at this point, but I wasn't trying to shout, just to draw attention to the essential point of my comment. My bad!

            – Prestaul
            Aug 29 '14 at 22:11















            62














            You are using a single RegExp object and executing it multiple times. On each successive execution it continues on from the last match index.



            You need to "reset" the regex to start from the beginning before each execution:



            result.push(re.test('Foo Bar'));
            re.lastIndex = 0;
            result.push(re.test('Foo Bar'));
            // result is now [true, true]


            Having said that it may be more readable to create a new RegExp object each time (overhead is minimal as the RegExp is cached anyway):



            result.push((/Foo B/gi).test(stringA));
            result.push((/Foo B/gi).test(stringB));





            share|improve this answer




























              62














              You are using a single RegExp object and executing it multiple times. On each successive execution it continues on from the last match index.



              You need to "reset" the regex to start from the beginning before each execution:



              result.push(re.test('Foo Bar'));
              re.lastIndex = 0;
              result.push(re.test('Foo Bar'));
              // result is now [true, true]


              Having said that it may be more readable to create a new RegExp object each time (overhead is minimal as the RegExp is cached anyway):



              result.push((/Foo B/gi).test(stringA));
              result.push((/Foo B/gi).test(stringB));





              share|improve this answer


























                62












                62








                62







                You are using a single RegExp object and executing it multiple times. On each successive execution it continues on from the last match index.



                You need to "reset" the regex to start from the beginning before each execution:



                result.push(re.test('Foo Bar'));
                re.lastIndex = 0;
                result.push(re.test('Foo Bar'));
                // result is now [true, true]


                Having said that it may be more readable to create a new RegExp object each time (overhead is minimal as the RegExp is cached anyway):



                result.push((/Foo B/gi).test(stringA));
                result.push((/Foo B/gi).test(stringB));





                share|improve this answer













                You are using a single RegExp object and executing it multiple times. On each successive execution it continues on from the last match index.



                You need to "reset" the regex to start from the beginning before each execution:



                result.push(re.test('Foo Bar'));
                re.lastIndex = 0;
                result.push(re.test('Foo Bar'));
                // result is now [true, true]


                Having said that it may be more readable to create a new RegExp object each time (overhead is minimal as the RegExp is cached anyway):



                result.push((/Foo B/gi).test(stringA));
                result.push((/Foo B/gi).test(stringB));






                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Oct 5 '09 at 15:40









                Roatin MarthRoatin Marth

                17.9k34151




                17.9k34151























                    34














                    RegExp.prototype.test updates the regular expressions' lastIndex property so that each test will start where the last one stopped. I'd suggest using String.prototype.match since it doesn't update the lastIndex property:



                    !!'Foo Bar'.match(re); // -> true
                    !!'Foo Bar'.match(re); // -> true


                    Note: !! converts it to a boolean and then inverts the boolean so it reflects the result.



                    Alternatively, you could just reset the lastIndex property:



                    result.push(re.test('Foo Bar'));
                    re.lastIndex = 0;
                    result.push(re.test('Foo Bar'));





                    share|improve this answer




























                      34














                      RegExp.prototype.test updates the regular expressions' lastIndex property so that each test will start where the last one stopped. I'd suggest using String.prototype.match since it doesn't update the lastIndex property:



                      !!'Foo Bar'.match(re); // -> true
                      !!'Foo Bar'.match(re); // -> true


                      Note: !! converts it to a boolean and then inverts the boolean so it reflects the result.



                      Alternatively, you could just reset the lastIndex property:



                      result.push(re.test('Foo Bar'));
                      re.lastIndex = 0;
                      result.push(re.test('Foo Bar'));





                      share|improve this answer


























                        34












                        34








                        34







                        RegExp.prototype.test updates the regular expressions' lastIndex property so that each test will start where the last one stopped. I'd suggest using String.prototype.match since it doesn't update the lastIndex property:



                        !!'Foo Bar'.match(re); // -> true
                        !!'Foo Bar'.match(re); // -> true


                        Note: !! converts it to a boolean and then inverts the boolean so it reflects the result.



                        Alternatively, you could just reset the lastIndex property:



                        result.push(re.test('Foo Bar'));
                        re.lastIndex = 0;
                        result.push(re.test('Foo Bar'));





                        share|improve this answer













                        RegExp.prototype.test updates the regular expressions' lastIndex property so that each test will start where the last one stopped. I'd suggest using String.prototype.match since it doesn't update the lastIndex property:



                        !!'Foo Bar'.match(re); // -> true
                        !!'Foo Bar'.match(re); // -> true


                        Note: !! converts it to a boolean and then inverts the boolean so it reflects the result.



                        Alternatively, you could just reset the lastIndex property:



                        result.push(re.test('Foo Bar'));
                        re.lastIndex = 0;
                        result.push(re.test('Foo Bar'));






                        share|improve this answer












                        share|improve this answer



                        share|improve this answer










                        answered Oct 5 '09 at 15:41









                        JamesJames

                        91.2k28147168




                        91.2k28147168























                            9














                            Removing global g flag will fix your problem.



                            var re = new RegExp(query, 'gi');


                            Should be



                            var re = new RegExp(query, 'i');





                            share|improve this answer






























                              9














                              Removing global g flag will fix your problem.



                              var re = new RegExp(query, 'gi');


                              Should be



                              var re = new RegExp(query, 'i');





                              share|improve this answer




























                                9












                                9








                                9







                                Removing global g flag will fix your problem.



                                var re = new RegExp(query, 'gi');


                                Should be



                                var re = new RegExp(query, 'i');





                                share|improve this answer















                                Removing global g flag will fix your problem.



                                var re = new RegExp(query, 'gi');


                                Should be



                                var re = new RegExp(query, 'i');






                                share|improve this answer














                                share|improve this answer



                                share|improve this answer








                                edited Nov 25 '15 at 20:41









                                Jonatas Walker

                                8,21342155




                                8,21342155










                                answered Nov 12 '13 at 21:34









                                user2572074user2572074

                                9111




                                9111























                                    0














                                    Using the /g flag tells it to continue searching after a hit.



                                    If the match succeeds, the exec() method returns an array and updates properties of the regular expression object.



                                    Before your first search:



                                    myRegex.lastIndex
                                    //is 0


                                    After the first search



                                    myRegex.lastIndex
                                    //is 8


                                    Remove the g and it exits the search after each call to exec().






                                    share|improve this answer




























                                      0














                                      Using the /g flag tells it to continue searching after a hit.



                                      If the match succeeds, the exec() method returns an array and updates properties of the regular expression object.



                                      Before your first search:



                                      myRegex.lastIndex
                                      //is 0


                                      After the first search



                                      myRegex.lastIndex
                                      //is 8


                                      Remove the g and it exits the search after each call to exec().






                                      share|improve this answer


























                                        0












                                        0








                                        0







                                        Using the /g flag tells it to continue searching after a hit.



                                        If the match succeeds, the exec() method returns an array and updates properties of the regular expression object.



                                        Before your first search:



                                        myRegex.lastIndex
                                        //is 0


                                        After the first search



                                        myRegex.lastIndex
                                        //is 8


                                        Remove the g and it exits the search after each call to exec().






                                        share|improve this answer













                                        Using the /g flag tells it to continue searching after a hit.



                                        If the match succeeds, the exec() method returns an array and updates properties of the regular expression object.



                                        Before your first search:



                                        myRegex.lastIndex
                                        //is 0


                                        After the first search



                                        myRegex.lastIndex
                                        //is 8


                                        Remove the g and it exits the search after each call to exec().







                                        share|improve this answer












                                        share|improve this answer



                                        share|improve this answer










                                        answered Sep 21 '17 at 0:33









                                        Scott SchlechtleitnerScott Schlechtleitner

                                        11314




                                        11314























                                            0














                                            I had the function:



                                            function parseDevName(name) {
                                            var re = /^([^-]+)-([^-]+)-([^-]+)$/g;
                                            var match = re.exec(name);
                                            return match.slice(1,4);
                                            }

                                            var rv = parseDevName("BR-H-01");
                                            rv = parseDevName("BR-H-01");


                                            The first call works.
                                            The second call doesn't. The slice operation complains about a null value. I assume this is because of the re.lastIndex. This is strange because I would expect a new RegExp to be allocated each time the function is called and not shared across multiple invocations of my function.



                                            When I changed it to:



                                            var re = new RegExp('^([^-]+)-([^-]+)-([^-]+)$', 'g');


                                            Then I don't get the lastIndex holdover effect. It works as I would expect it to.






                                            share|improve this answer




























                                              0














                                              I had the function:



                                              function parseDevName(name) {
                                              var re = /^([^-]+)-([^-]+)-([^-]+)$/g;
                                              var match = re.exec(name);
                                              return match.slice(1,4);
                                              }

                                              var rv = parseDevName("BR-H-01");
                                              rv = parseDevName("BR-H-01");


                                              The first call works.
                                              The second call doesn't. The slice operation complains about a null value. I assume this is because of the re.lastIndex. This is strange because I would expect a new RegExp to be allocated each time the function is called and not shared across multiple invocations of my function.



                                              When I changed it to:



                                              var re = new RegExp('^([^-]+)-([^-]+)-([^-]+)$', 'g');


                                              Then I don't get the lastIndex holdover effect. It works as I would expect it to.






                                              share|improve this answer


























                                                0












                                                0








                                                0







                                                I had the function:



                                                function parseDevName(name) {
                                                var re = /^([^-]+)-([^-]+)-([^-]+)$/g;
                                                var match = re.exec(name);
                                                return match.slice(1,4);
                                                }

                                                var rv = parseDevName("BR-H-01");
                                                rv = parseDevName("BR-H-01");


                                                The first call works.
                                                The second call doesn't. The slice operation complains about a null value. I assume this is because of the re.lastIndex. This is strange because I would expect a new RegExp to be allocated each time the function is called and not shared across multiple invocations of my function.



                                                When I changed it to:



                                                var re = new RegExp('^([^-]+)-([^-]+)-([^-]+)$', 'g');


                                                Then I don't get the lastIndex holdover effect. It works as I would expect it to.






                                                share|improve this answer













                                                I had the function:



                                                function parseDevName(name) {
                                                var re = /^([^-]+)-([^-]+)-([^-]+)$/g;
                                                var match = re.exec(name);
                                                return match.slice(1,4);
                                                }

                                                var rv = parseDevName("BR-H-01");
                                                rv = parseDevName("BR-H-01");


                                                The first call works.
                                                The second call doesn't. The slice operation complains about a null value. I assume this is because of the re.lastIndex. This is strange because I would expect a new RegExp to be allocated each time the function is called and not shared across multiple invocations of my function.



                                                When I changed it to:



                                                var re = new RegExp('^([^-]+)-([^-]+)-([^-]+)$', 'g');


                                                Then I don't get the lastIndex holdover effect. It works as I would expect it to.







                                                share|improve this answer












                                                share|improve this answer



                                                share|improve this answer










                                                answered Jun 28 '18 at 23:05









                                                ChelmiteChelmite

                                                216114




                                                216114






























                                                    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%2f1520800%2fwhy-does-a-regexp-with-global-flag-give-wrong-results%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

                                                    Monofisismo

                                                    Angular Downloading a file using contenturl with Basic Authentication

                                                    Olmecas