Why Does JavaScript's Regex.Exec() Not Always Return the Same Value

Why does Javascript's regex.exec() not always return the same value?

A JavaScript RegExp object is stateful.

When the regex is global, if you call a method on the same regex object, it will start from the index past the end of the last match.

When no more matches are found, the index is reset to 0 automatically.


To reset it manually, set the lastIndex property.

reg.lastIndex = 0;

This can be a very useful feature. You can start the evaluation at any point in the string if desired, or if in a loop, you can stop it after a desired number of matches.


Here's a demonstration of a typical approach to using the regex in a loop. It takes advantage of the fact that exec returns null when there are no more matches by performing the assignment as the loop condition.

var re = /foo_(\d+)/g,
str = "text foo_123 more text foo_456 foo_789 end text",
match,
results = [];

while (match = re.exec(str))
results.push(+match[1]);

DEMO: http://jsfiddle.net/pPW8Y/


If you don't like the placement of the assignment, the loop can be reworked, like this for example...

var re = /foo_(\d+)/g,
str = "text foo_123 more text foo_456 foo_789 end text",
match,
results = [];

do {
match = re.exec(str);
if (match)
results.push(+match[1]);
} while (match);

DEMO: http://jsfiddle.net/pPW8Y/1/

Why is regex.exec() return type is a boolean?

Because arr isn't the result of exec, it's the result of !== (which should be either true or false).

In other words, x = y !== z parses as x = (y !== z), not (x = y) !== z.

You probably meant to write

while ((arr = pattern.exec(str)) !== null) {

instead.

REGEX: match and exec returns different results

As described in String.prototype.match() MDN documentation:

if you want to obtain capture groups and the global flag is set, you
need to use RegExp.exec() instead.

So, to obtain the same result with String.prototype.match(), remove the g flag from the regular expression:

let regexp = /Rim.*?vert\s(\d*)cm/ //<-- Removed the "g" flag.let content = "BEONE SPS SPIRIT, 2012y.b.,26 Rim - BEONE aluminium, vert 51cm «L»,ЕТТ600mm, 835 37 38";
let resultMatch = content.match(regexp);console.log('result with match:', resultMatch);
let resultExec = regexp.exec(content);console.log('result with exec:', resultExec);

RegExp object won't execute more than once, why?

The difference lies in the /g flag that you've passed to both regexes. From MDN:

RegExp.prototype.exec() method with the g flag returns each match and its position iteratively.

const str = 'fee fi fo fum';
const re = /\w+\s/g;

console.log(re.exec(str)); // ["fee ", index: 0, input: "fee fi fo fum"]
console.log(re.exec(str)); // ["fi ", index: 4, input: "fee fi fo fum"]
console.log(re.exec(str)); // ["fo ", index: 7, input: "fee fi fo fum"]
console.log(re.exec(str)); // null

So /g on a regex turns the regex object itself into a funny sort of mutable state-tracker. When you call exec on a /g regex, you're matching and also setting a parameter on that regex which remembers where it left off for next time. The intention is that if you match against the same string, you won't get the same match twice, allowing you to do mutable tricks with while loops similar to the sort of way you would write a global regex match in Perl.

But since you're matching on two different strings, it causes problems. Let's look at a simplified example.

const re = /a/g;
re.exec("ab"); // Fine, we match against "a"
re.exec("ba"); // We start looking at the second character, so we match the "a" there.
re.exec("ab"); // We start looking at the third character, so we get *no* match.

Whereas in the case where you produce the regex every time, you never see this statefulness, since the regex object is made anew each time.

So the summary is: Don't use /g if you're planning to reuse the regex against multiple strings.

Regex exec function not returning correct result in Javascript

It is just how [RegExp.exec()][1] works: the lastIndex property got set to 20 after the first match and you did not reset it. The second time, it could not match anything as it started looking for a match at Position 20. This all happens this way because the regex is built with the global modifier /g.

If your regular expression uses the "g" flag, you can use the exec() method multiple times to find successive matches in the same string. When you do so, the search starts at the substring of str specified by the regular expression's lastIndex property

You can reset the regexStr.lastIndex manually:

function parseClassTime(times) {    console.log("Input: " + times);    var timeArr = [];    var finalArr = [];    regexStr = /(\d{1,2}:\d{2}[ap]m) - (\d{1,2}:\d{2}[ap]m) \((\w{1,5})\)/g;    if (times.indexOf(") ") > -1) {        times = times.replace(") ", ")&");        timeArr = times.split("&");    } else {        timeArr.push(times);    }    console.log("timeArr: " + timeArr);    for (i = 0; i < timeArr.length; i++) {        regexStr.lastIndex = 0;              // <= HERE!!        console.log(i + ":" + timeArr[i]);        console.log("regexResult: " + regexStr.exec(timeArr[i]));    }};
parseClassTime("7:55am - 9:10am (TR) 8:10am - 9:00am (W)");

JavaScript regex exec() returns match repeated in a list, why?

You're NOT getting exactly same items in the printed list.

  • 1st one is having same spaces, representing $0
  • 2nd one is text without spaces, representing $1

If you change your regex to this:

var tx = /\s*(?:\(|\)|[^\s()]+|$)/g;

Then you will get single item in the printed list.

Regex exec only returning first match

RegExp.exec is only able to return a single match result at once.

In order to retrieve multiple matches you need to run exec on the expression object multiple times. For example, using a simple while loop:

var ptrn = /[a-zA-Z_][a-zA-Z0-9_]*|'(?:\\.|[^'])*'?|"(?:\\.|[^"])*"?|-?[0-9]+|#[^\n\r]*|./mg;

var match;
while ((match = ptrn.exec(input)) != null) {
console.log(match);
}

This will log all matches to the console.

Note that in order to make this work, you need to make sure that the regular expression has the g (global) flag. This flag makes sure that after certain methods are executed on the expression, the lastIndex property is updated, so further calls will start after the previous result.

The regular expression will also need to be declared outside of the loop (as shown in the example above). Otherwise, the expression object would be recreated on every iteration and then the lastIndex would obviously reset every time, resulting in an infinite loop.

Javascript regexp exec doesn't work

The problem is here

new RegExp("^(?=\d)((\d+)(h|:))?\s*((\d+)m?)?$", "g");

When you create a new Regular Expression through the constructor, you provide strings. In string literals, the backslash character (\) means ‘escape the next character’.

You have to escape those backslashes, so they won't escape their subsequent character. So the correct version is:

new RegExp("^(?=\\d)((\\d+)(h|:))?\\s*((\\d+)m?)?$", "g");

See this article on values, variables, and literals from MDN for more information on escaping characters in JavaScript.



Related Topics



Leave a reply



Submit