Why does a RegExp with global flag give wrong results?
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"));
javascript regex
add a comment |
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"));
javascript regex
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 tore
.
– thdoan
Oct 10 '18 at 17:26
add a comment |
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"));
javascript regex
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
javascript regex
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 tore
.
– thdoan
Oct 10 '18 at 17:26
add a comment |
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 tore
.
– 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
add a comment |
6 Answers
6
active
oldest
votes
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:
- Let S be the value of ToString(string).
- Let length be the length of S.
- Let lastIndex be the value of the lastIndex property.
- Let i be the value of ToInteger(lastIndex).
- If the global property is false, let i = 0.
- If I < 0 or I > length then set lastIndex to 0 and return null.
- 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.
- Let i = i+1.
- Go to step 6.
- Let e be r's endIndex value.
- If the global property is true, set lastIndex to e.
- Let n be the length of r's captures array. (This is the same
value as 15.10.2.1's
NCapturingParens.)
- 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.
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 oflastIndex
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
add a comment |
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));
add a comment |
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'));
add a comment |
Removing global g
flag will fix your problem.
var re = new RegExp(query, 'gi');
Should be
var re = new RegExp(query, 'i');
add a comment |
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().
add a comment |
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.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%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
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:
- Let S be the value of ToString(string).
- Let length be the length of S.
- Let lastIndex be the value of the lastIndex property.
- Let i be the value of ToInteger(lastIndex).
- If the global property is false, let i = 0.
- If I < 0 or I > length then set lastIndex to 0 and return null.
- 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.
- Let i = i+1.
- Go to step 6.
- Let e be r's endIndex value.
- If the global property is true, set lastIndex to e.
- Let n be the length of r's captures array. (This is the same
value as 15.10.2.1's
NCapturingParens.)
- 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.
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 oflastIndex
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
add a comment |
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:
- Let S be the value of ToString(string).
- Let length be the length of S.
- Let lastIndex be the value of the lastIndex property.
- Let i be the value of ToInteger(lastIndex).
- If the global property is false, let i = 0.
- If I < 0 or I > length then set lastIndex to 0 and return null.
- 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.
- Let i = i+1.
- Go to step 6.
- Let e be r's endIndex value.
- If the global property is true, set lastIndex to e.
- Let n be the length of r's captures array. (This is the same
value as 15.10.2.1's
NCapturingParens.)
- 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.
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 oflastIndex
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
add a comment |
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:
- Let S be the value of ToString(string).
- Let length be the length of S.
- Let lastIndex be the value of the lastIndex property.
- Let i be the value of ToInteger(lastIndex).
- If the global property is false, let i = 0.
- If I < 0 or I > length then set lastIndex to 0 and return null.
- 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.
- Let i = i+1.
- Go to step 6.
- Let e be r's endIndex value.
- If the global property is true, set lastIndex to e.
- Let n be the length of r's captures array. (This is the same
value as 15.10.2.1's
NCapturingParens.)
- 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.
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:
- Let S be the value of ToString(string).
- Let length be the length of S.
- Let lastIndex be the value of the lastIndex property.
- Let i be the value of ToInteger(lastIndex).
- If the global property is false, let i = 0.
- If I < 0 or I > length then set lastIndex to 0 and return null.
- 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.
- Let i = i+1.
- Go to step 6.
- Let e be r's endIndex value.
- If the global property is true, set lastIndex to e.
- Let n be the length of r's captures array. (This is the same
value as 15.10.2.1's
NCapturingParens.)
- 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.
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 oflastIndex
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
add a comment |
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 oflastIndex
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
add a comment |
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));
add a comment |
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));
add a comment |
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));
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));
answered Oct 5 '09 at 15:40
Roatin MarthRoatin Marth
17.9k34151
17.9k34151
add a comment |
add a comment |
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'));
add a comment |
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'));
add a comment |
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'));
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'));
answered Oct 5 '09 at 15:41
JamesJames
91.2k28147168
91.2k28147168
add a comment |
add a comment |
Removing global g
flag will fix your problem.
var re = new RegExp(query, 'gi');
Should be
var re = new RegExp(query, 'i');
add a comment |
Removing global g
flag will fix your problem.
var re = new RegExp(query, 'gi');
Should be
var re = new RegExp(query, 'i');
add a comment |
Removing global g
flag will fix your problem.
var re = new RegExp(query, 'gi');
Should be
var re = new RegExp(query, 'i');
Removing global g
flag will fix your problem.
var re = new RegExp(query, 'gi');
Should be
var re = new RegExp(query, 'i');
edited Nov 25 '15 at 20:41
Jonatas Walker
8,21342155
8,21342155
answered Nov 12 '13 at 21:34
user2572074user2572074
9111
9111
add a comment |
add a comment |
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().
add a comment |
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().
add a comment |
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().
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().
answered Sep 21 '17 at 0:33
Scott SchlechtleitnerScott Schlechtleitner
11314
11314
add a comment |
add a comment |
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.
add a comment |
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.
add a comment |
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.
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.
answered Jun 28 '18 at 23:05
ChelmiteChelmite
216114
216114
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f1520800%2fwhy-does-a-regexp-with-global-flag-give-wrong-results%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
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