61

Update: This question is a near duplicate of this

I'm sure the answer to my question is out there, but I couldn't find the words to express it succinctly. I am trying to do the following with JavaScript regex:

var input = "'Warehouse','Local Release','Local Release DA'";
var regex = /'(.*?)'/g;

console.log(input.match(regex));

// Actual:
// ["'Warehouse'", "'Local Release'", "'Local Release DA'"]

// What I'm looking for (without the '):
// ["Warehouse", "Local Release", "Local Release DA"]

Is there a clean way to do this with JavaScript regex? Obviously I could strip out the 's myself, but I'm looking for the correct way to caputre globally matched groupings with regex.

shaedrich
  • 5,457
  • 3
  • 26
  • 42
Jondlm
  • 8,764
  • 2
  • 24
  • 30
  • 1
    possible duplicate of [How do you access the matched groups in a javascript regex?](http://stackoverflow.com/questions/432493/how-do-you-access-the-matched-groups-in-a-javascript-regex) – Barmar Nov 11 '13 at 18:56
  • Yep, it's definitely a duplicate, I wasn't sure how to search for my question :/ – Jondlm Nov 11 '13 at 19:01
  • I found it by searching for _[javascript] [regex] global capture group_. – Barmar Nov 11 '13 at 20:23

8 Answers8

114

To do this with a regex, you will need to iterate over it with .exec() in order to get multiple matched groups. The g flag with match will only return multiple whole matches, not multiple sub-matches like you wanted. Here's a way to do it with .exec().

var input = "'Warehouse','Local Release','Local Release DA'";
var regex = /'(.*?)'/g;

var matches, output = [];
while (matches = regex.exec(input)) {
    output.push(matches[1]);
}
// result is in output here

Working demo: http://jsfiddle.net/jfriend00/VSczR/


With certain assumptions about what's in the strings, you could also just use this:

var input = "'Warehouse','Local Release','Local Release DA'";
var output = input.replace(/^'|'$/, "").split("','");

Working demo: http://jsfiddle.net/jfriend00/MFNm3/


Note: With modern Javascript engines as of 2021, you can use str.matchAll(regex) and get all matches in one function call.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • Added a non-regex way to also do this. – jfriend00 Nov 11 '13 at 19:07
  • I applied this loop with this regex `/]+?src=(?:(?:'([^']*)')|(?:"([^"]*)")|([^\s]*))/i` and console don't respond and chrome using 1 full cpu core – jscripter Jul 09 '15 at 03:17
  • Oh I forgot the `g` modifier. Now it's ok – jscripter Jul 09 '15 at 03:31
  • 1
    this will fail in jslink.. do this instead while ((matches = regex.exec(input)) !== null){ – keithics May 19 '16 at 12:08
  • @keithics - What in the world is jslink returning that is not `null`, but is falsey that would make the original code not work? This is weird. `.exec()` should return an array or `null` so the original code should detect no match just fine. – jfriend00 May 19 '16 at 14:38
  • @keithics - OK, there's nothing wrong with the code then. That's just a false warning. Given we know what `.exec()` returns, the code is no better or safer by changing to `!== null`. That's just an overcautious warning by jsHint. – jfriend00 May 22 '16 at 04:24
  • [Mozilla uses](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec) `!== null` – Slbox Jul 01 '20 at 01:22
  • The code goes into infinite loop when the pattern matches the empty string, e.g. `regex = /.*/g`. – umitu Nov 05 '21 at 20:40
  • @umitu - You'd have to explain what exact problem you're trying to solve using that regex (perhaps write your own question). That regex matches the entire string. These days [`.matchAll()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/matchAll) can often be used instead of a loop, but again, I don't really know what you're trying to accomplish. – jfriend00 Nov 05 '21 at 23:02
  • @jfriend00 When I tried to match text inside parentheses with `regex = /(?<=\()[^)]*(?=\))/g`, I got an infinite loop with `"()"`. matchAll() works fine. – umitu Nov 06 '21 at 10:11
9

There is an ECMAScript proposal called String.prototype.matchAll() that would fulfill your needs.

shaedrich
  • 5,457
  • 3
  • 26
  • 42
9

String.prototype.matchAll is now well supported in modern browsers as well as Node.js. This can be used like so:

const matches = Array.from(myString.matchAll(/myRegEx/g)).map(match => match[1]);

Note that the passed RegExp must have the global flag or an error will be thrown.

Conveniently, this does not throw an error when no matches are found as .matchAll always returns an iterator (vs .match() returning null).


For this specific example:

var input = "'Warehouse','Local Release','Local Release DA'";
var regex = /'(.*?)'/g;

var matches = Array.from(input.matchAll(regex)).map(match => match[1]);
// [ "Warehouse", "Local Release", "Local Release DA" ]
derpedy-doo
  • 1,097
  • 1
  • 18
  • 22
  • 2
    `Array.from` accepts a `mapFn` as a second argument. So what's also possible is: `Array.from(myString.matchAll(/myRegEx/g), m => m[1])`. MDN uses it as an example in their `matchAll` documentation, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/matchAll – Melvin Roest Mar 04 '21 at 17:29
5

Not very generic solution since lookbehind isn't supported in Javascript but for given input this regex should work:

m = input.match(/([^',]+)(?=')/g);
//=> ["Warehouse", "Local Release", "Local Release DA"]
anubhava
  • 761,203
  • 64
  • 569
  • 643
3

With es2020 you can use matchAll:

var input = "'Warehouse','Local Release','Local Release DA'";
var regex = /'(.*?)'/g;

const match_all = [...input.matchAll(regex)];

If you're using typescript, don't forget to set it in tsconfig.json:

"compilerOptions": {
    "lib": ["es2020.string"]
}
João Paulo
  • 6,300
  • 4
  • 51
  • 80
1

Try something like input.replace(regex, "$1") to get the results of your capture group.

cjc343
  • 3,735
  • 1
  • 29
  • 34
-1

this regex works but with defined characters...

var input = "'Warehouse','Local Release','Local Release DA'";

var r =/'[\w\s]+'/gi;
console.log(input.match(regex));
Techsin
  • 514
  • 3
  • 18
-2

EDIT: This won't work in javascript, but it does work in java. Sorry bout that.

yes, it's called a "look ahead" and a "look behind"

(?<=').*?(?=')
  • (?=') looks ahead for the '
  • (?<=') looks behind for the '

test it out here

Josh T
  • 564
  • 3
  • 12