10

Is there any better solution to this here? I try to avoid the assignment inside while but still be able to loop through the matches and use the captured groups.

var match = "";
var CSS_URL_PATTERN = /url\s*\(\s*["|']?(.*?)\s*["|']?\)\s*/gm
while ((match = CSS_URL_PATTERN.exec(someBigCSSString)) !== null) {
   // Do stuff here per match…
}

I added a bit more context to this question, also a RegEx example.

  • 1
    Why not use `match`. It will return an array which you can loop. You way you designed it now will be an endless loop. – Mouser Aug 02 '15 at 21:13
  • What are you trying to do in this loop? – eddyjs Aug 02 '15 at 21:14
  • *"avoid the assignment inside while"* - why? you can avoid it but it's really not that bad. – dfsq Aug 02 '15 at 21:17
  • It won't work properly whether it has `g` flag. In this case, it should be assigned outside loop. – w35l3y Aug 02 '15 at 21:57
  • @dfsq Not sure about that. The only reason I can think of is that the assignment '=' can be easily misread with a comparison '==='. It simply doesn't feel right tbh and ESLint complains about it (no-cond-assign). –  Aug 03 '15 at 05:51

6 Answers6

3

I always do as follows when I need .exec:

var re = /.../g, match;
while (match = re.exec(...)) {
    //...
}

Regular expressions with g flag causes infinite effect when it is in the loop condition.

What are the differences between Fx 3.x and Fx 4.x that made many userscripts stop working?

Community
  • 1
  • 1
w35l3y
  • 8,613
  • 3
  • 39
  • 51
  • 1
    Aye … I have the regex declaration outside of the loop. Amended my question for clarity. –  Aug 03 '15 at 05:43
  • @wittgenstein, my answer is still the same. I don't think there any better and shorter way to do what you want without missing legibility. – w35l3y Aug 03 '15 at 22:52
3

If you want to avoid the assignment inside while you can use a do while loop:

var URLRegExp = /url\s*\(\s*["|']?(.*?)\s*["|']?\)\s*/g
var match
do {
  match = URLRegExp.exec(bootstrap)
  if (match) {
    // Do stuff here per match...
  }
} while (match)

But a while loop it's simpler and avoids unnecesary code like the if statement inside do. An assignment inside a condition is not as bad as people think if you understand what's the behaviour of the code and what's the context.

Another case is when you're using a linter to avoid to mistype a comparison operator (such as ==) as an assignment operator, but allmost all the linters using now support using comments to modify linter behaviour in a specific part of the code so this isn't really a problem

Alex Guerrero
  • 2,109
  • 1
  • 19
  • 28
0

var match = "Is This The Real Life|Is This Just Fantasy|Caught In A Landslide|No Escape From Reality|".match(/.+?\|/ig);

//print result using join
document.body.innerHTML += match.join("<br />");
document.body.innerHTML += "<br /><br />";
//print results using for loop and strip |
for (var i = 0; i < match.length; ++i)
{
    document.body.innerHTML += match[i].slice(0, -1) + "<br />";
}

This will avoid a loop altogether. match returns an array. You can either loop it and do stuff with it, or like I did print the results using join. match accepts regex-patterns.

Mouser
  • 13,132
  • 3
  • 28
  • 54
0
var matches = someString.match(REGEX_PATTERN);
for (var i = 0; matches && i < matches.length; i++) {
  // Do stuff here per match…
}
Yunchi
  • 5,529
  • 2
  • 17
  • 18
  • 1
    If REGEX_PATTERN needs to capture groups and the global flag is set, you need to use `RegExp.exec()` – w35l3y Aug 02 '15 at 23:32
  • 1
    @w35l3y didn't realize that. TIL. The question says nothing about what he needs to do though... – Yunchi Aug 03 '15 at 01:21
  • @w35l3y Exactly. I added the regex to the question. Sorry, I missed it when I originally posted. –  Aug 03 '15 at 05:42
0
someString.replace(REGEX_PATTERN,
    function (wholeMatch, group1, group2/*...*/, index, sourceString) {
        // Do stuff here per match…
    });
Markus Jarderot
  • 86,735
  • 21
  • 136
  • 138
0

In 2023 String.prototype.matchAll works as an alternative to the while loop:

const CSS_URL_PATTERN = /url\s*\(\s*["|']?(.*?)\s*["|']?\)\s*/gm
[...someBigCSSString.matchAll(CSS_URL_PATTERN)].forEach(match => {
  // Do stuff here per match…
});
gztomas
  • 3,030
  • 3
  • 27
  • 38