72

Here is the case: I want to find the elements which match the regex...

targetText = "SomeT1extSomeT2extSomeT3extSomeT4extSomeT5extSomeT6ext"

and I use the regex in javascript like this

reg = new RegExp(/e(.*?)e/g);   
var result = reg.exec(targetText);

and I only get the first one, but not the follow.... I can get the T1 only, but not T2, T3 ... ...

1
  • 3
    Can anyone suggest a for loop way to do it?
    – DNB5brims
    Commented Aug 3, 2009 at 12:34

9 Answers 9

91

function doSomethingWith(result) {
  console.log(result)
}

const targetText = "SomeT1extSomeT2extSomeT3extSomeT4extSomeT5extSomeT6ext"
const reg = /e(.*?)e/g;
let result;
while ((result = reg.exec(targetText)) !== null) {
  doSomethingWith(result);
}

8
  • 8
    Note that the regex must be assigned to an object before using in this manner: /e(.*?)e/.exec(...) will give an infinite loop.
    – ARM
    Commented May 24, 2017 at 18:36
  • 3
    @RaviParekh: did you add the /g modifier?
    – chaos
    Commented Nov 30, 2017 at 15:26
  • 3
    For posterity's sake, the RegExp needs to be declared outside of the while loop; otherwise you'll still get an infinite loop.
    – Native Dev
    Commented Mar 13, 2018 at 16:04
  • 3
    You can also shorten the while expression: while(result = reg.exec(targetText)) { leveraging the "false" resolve.
    – Native Dev
    Commented Mar 13, 2018 at 16:10
  • 2
    @Redtopia You must only increment lastIndex manually (reg.lastIndex = result.index + 1;) if you are not using the g (global) flag in your regex. The global flag will automatically move to the next match, however, the disadvantage is that if you want to re-use a global regex, you must reset reg.lastIndex = 0; before you match a new string.
    – Yeti
    Commented Sep 1, 2021 at 11:54
71

Three approaches depending on what you want to do with it:

  • Loop through each match: .match

    targetText.match(/e(.*?)e/g).forEach((element) => {
       // Do something with each element
    });
    
  • Loop through and replace each match on the fly: .replace

    const newTargetText = targetText.replace(/e(.*?)e/g, (match, $1) => {
      // Return the replacement leveraging the parameters.
    });
    
  • Loop through and do something on the fly: .exec

    const regex = /e(.*?)e/g;  // Must be declared outside the while expression, 
                               // and must include the global "g" flag.
    
    let result;
    while(result = regex.exec(targetText)) {
      // Do something with result[0].
    } 
    
5
  • Ironically my Lint wants to put == in place of = in the while expression.
    – Gherman
    Commented Nov 8, 2019 at 15:36
  • To make eslint accept the single = the assignment can be surrounded by parentheses like so: while ((result = regex.exec(targetText)))
    – sheean
    Commented Nov 14, 2019 at 9:22
  • In the second example there, is match a key word or a variable? And if it's a variable what is it holding?
    – Cole Perry
    Commented Jan 22, 2020 at 21:26
  • @ColePerry match is the whole RegExp match, and $1 is the first capture group (), in that example, only one.
    – Native Dev
    Commented Jan 31, 2020 at 22:09
  • 1
    Here, only replace will work, because in Node.js the global match/exec returns only total match without groups.
    – mirik
    Commented Aug 31, 2020 at 16:14
13

Try using match() on the string instead of exec(), though you could loop with exec as well. Match should give you the all the matches at one go. I think you can omit the global specifier as well.

reg = new RegExp(/e(.*?)e/);   
var matches = targetText.match(reg);
6
  • 11
    Don't link to w3schools. They are unaffiliated with W3C and have a lot of wrong information. See w3fools.com.
    – dbkaplun
    Commented Jun 24, 2012 at 5:21
  • 8
    @MindVirus - if you'd bother to check, they've cleaned up a lot of the stuff that w3fools.com pointed out. I still use them as a quick, though not definitive, resource. Much like one might use a cheat sheet over K&R C to look up something simple.
    – tvanfosson
    Commented Jun 24, 2012 at 13:34
  • 1
    As an intermediate dev, I've already encountered a good half dozen clear errors at w3schools. They're off my party list. Commented Jul 18, 2013 at 0:17
  • 2
    MDN reference for String.prototype.matchdeveloper.mozilla.org/en/docs/Web/JavaScript/Reference/… Commented Dec 7, 2015 at 9:56
  • 3
    the difference is that you don't get the captured groups with String.match, while RegExp.exec does.
    – Vitim.us
    Commented May 23, 2018 at 19:11
4

I kept getting infinite loops while following the advice above, for example:

var reg = /e(.*?)e/g;
var result;
while((result = reg.exec(targetText)) !== null) {
    doSomethingWith(result);
}

The object that was assigned to result each time was:

["", "", index: 50, input: "target text", groups: undefined]

So in my case I edited the above code to:

const reg = /e(.*?)e/g;
let result = reg.exec(targetText);
while(result[0] !== "") {
    doSomethingWith(result);
    result = reg.exec(targetText);
}
1
  • that's because of the regex. you have let to accept empty strings by putting a question mark
    – JSBach
    Commented Nov 6, 2020 at 3:49
2
targetText = "SomeT1extSomeT2extSomeT3extSomeT4extSomeT5extSomeT6ext"    
reg = new RegExp(/e(.*?)e/g);   
var result;
while (result = reg.exec(targetText))
{
    ...
}
1
  • It doesn't work. In JS regex cannot extract groups with global flag, so the user will receive only total match.
    – mirik
    Commented Aug 31, 2020 at 16:11
1

You could also use the String.replace method to loop through all elements.

result = [];
 // Just get all numbers
"SomeT1extSomeT2extSomeT3ext".replace(/(\d+?)/g, function(wholeMatch, num) {
  // act here or after the loop...
  console.log(result.push(num));
  return wholeMatch;
});
console.log(result); // ['1', '2', '3']

Greetings

1

I did this in a console session (Chrome).

> let reg = /[aeiou]/g;
undefined
> let text = "autoeciously";
undefined
> matches = text.matches(reg);
(7) ["a", "u", "o", "e", "i", "o", "u"]
> matches.forEach(x =>console.log(x));
a
u
o
e
i
o
u
0

Although @tvanfosson suggested in his answer, I'm adding the modified version for someone who only needs to get all matchings.

var targetText = "SomeT1extSomeT2extSomeT3extSomeT4extSomeT5extSomeT6ext";
var reg = /e(.*?)e/g;
var ss = targetText.match(reg); // ss = "eT1e,eT2e,eT3e,eT4e,eT5e,eT6e"
-1

I was actually dealing with this issue. I prefer Lambda functions for about everything.

reg = /e(.*?)e/gm;   
targetText.match(reg).forEach(element => console.log(element));
1
  • this only found the first match. Commented Oct 2, 2020 at 18:59

Not the answer you're looking for? Browse other questions tagged or ask your own question.