Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't String.match() produce expected results when a global flag is present? [duplicate]

I was trying this match

'/links/51f5382e7b7993e335000015'.match(/^\/links\/([0-9a-f]{24})$/g)

and got:

['/links/51f5382e7b7993e335000015']

while I was expecting:

['/links/51f5382e7b7993e335000015', '51f5382e7b7993e335000015']

I had no luck until I removed the global flag, which I did not think would impact results my results!

With the global flag removed,

'/links/51f5382e7b7993e335000015'.match(/^\/links\/([0-9a-f]{24})$/)

produced:

[ '/links/51f5382e7b7993e335000015',
  '51f5382e7b7993e335000015',
  index: 0,
  input: '/links/51f5382e7b7993e335000015' ]

which is cool, but reading the docs I can't figure out:

  • Why the first form didn't work
  • Why the global flag interfered with the () matching
  • How to get my expected result without the index and input properties

On JavaScript Regex and Submatches the top answer says:

Using String's match() function won't return captured groups if the global modifier is set, as you found out.

However,

> 'fofoofooofoooo'.match(/f(o+)/g) 
["fo", "foo", "fooo", "foooo"]

seems to produce captured groups just fine.

Thank you.

like image 534
Dmitry Minkovsky Avatar asked Jul 28 '13 20:07

Dmitry Minkovsky


1 Answers

From this msdn documentation for match method:

If the global flag (g) is not set, Element zero of the array contains the entire match, while elements 1 through n contain any submatches. This behavior is the same as the behavior of the exec Method (Regular Expression) (JavaScript) when the global flag is not set. If the global flag is set, elements 0 through n contain all matches that occurred.

Emphasis mine.

So, in your 1st case:

'/links/51f5382e7b7993e335000015'.match(/^\/links\/([0-9a-f]{24})$/g)

Since /g modifier is set, it will return just the complete matches that occurred, and not the submatches. That is why you just got an array with single element. As there is only 1 match for that regex.

2nd case:

'/links/51f5382e7b7993e335000015'.match(/^\/links\/([0-9a-f]{24})$/)

/g modifier is not set. So the array contains the complete match at 0th index. And further elements (1st index) in array are submatches - in this case, 1st capture group.


As for your last example:

'fofoofooofoooo'.match(/f(o+)/g)

Again, since /g modifier is set, it will return all the matches from the string, and not the submatches. So, in the string, the regex f(o+) matches 4 times:

fo    - 1st complete match (sub-match 'o' in 1st captured group ignored)
foo   - 2nd complete match (sub-match 'oo' ignored)
fooo  - 3rd complete match (sub-match 'ooo' ignored)
foooo - 4th complete match (sub-match 'oooo' ignored)

If you use the last regex without /g modifier, you would get each submatch as separate element, for the first match. Try:

'fofoofooofoooo'.match(/f(o+)/)

You will get:

["fo", "o"]  // With index and input element of course.

Without /g it just stops after first match (fo), and returns the entire match and sub-matches.

like image 112
Rohit Jain Avatar answered Nov 14 '22 02:11

Rohit Jain