Reuse-patterns-using-capture-groups specify number of patterns

Tell us what’s happening:
Okay, I can’t seem to pass the “42 42 42 42” test case that I’m supposed to NOT match. I’ve tried using quantity specifiers, but it either derails other test cases, or it becomes an invalid regex.
What am I missing?
Thanks.

Your code so far



let repeatNum = "42 42 42";
let reRegex = /(\d*)\s\1\s\1/; // Change this line
let result = reRegex.test(repeatNum);

Your browser information:

User Agent is: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36.

Link to the challenge:

6 Likes

Okay, so your regular expression will match anywhere in the string. It doesn’t have to match the entire string, and that’s where your problem lies.

If I did

let text = "hi there";
let reRegex = /hi/;
let result = reRegex.test(text);

Then it would match. This is because /hi/ matches the hi at the start of hi there, even though it doesn’t match the entire string. Same goes for your regular expression. It’s really close, but it will match the first three 42s, and stop there without making sure that there aren’t anymore.

To tell the regular expression that it must stop right there, you can put a $ sign. This is code for “the end of the string”. There’s an equivalent symbol for the start of a string, which is ^. (You also don’t want to match 52 42 42 42, so this will be needed too!)

Here’s are some examples of using $, and using ^ acts in the same way (remember to put it at the start instead, though).

let text, reRegex, result;

text = "hi there";
reRegex = /hi/;
result = reRegex.test(text); // true

text = "hi there";
reRegex = /hi$/;
result = reRegex.test(text); // false

 text = "wuddup hi";
 reRegex = /hi$/;
 result = reRegex.test(text); // true

Don’t forget, you’ll need to make sure that it starts at the start and ends at the end, so you’ll need to use both the ^ and the $. The ^ goes at the start (because it wouldn’t make sense to have the start of the string after matching a bunch of stuff already – for that would mean the string starts in the middle!); and the $ goes at the end (for similar reasons).

For example, the regular expression /^hi$/ will only match hi. It won’t match wuddup hi, nor will it match hi there

25 Likes

Ah! Thank you! This was very helpful!!

Oh oops! Thank you for your response… but I’ve spent a little white trying to create a Regular Expression simply to verify that there are exactly three occurrences of (\b\d+\b), but I can’t seem to find a way. You can’t reference capturing groups before they’ve been defined, so if there are four space-separated numbers, it’ll elect to omit the first one in the match. I don’t see how to force it to start a match there. Lookbehinds would also have to reference the capturing group before it’s been defined, as far as I can tell.

Do you have a solution yourself for this challenge which matches that test case, and if so, could you place it in spoiler tags – because I’m genuinely interested.

Is it possible that a Regular Expression simply cannot check that there are exactly three occurrences of \b\d+\b? If so, perhaps the challenge should be reworded?

I followed your solution and it almost worked.
It matched every test case except
"Your regex should have two spaces separating the three numbers."

Could you help ?

I used this
/^(\d+)(\s)\1\2\d+$/

Kay, that’s a wonderful Regular Expression you’ve produced. It should pass all the tests, but you’re trick of placing a space character into a capturing group and then referencing stuff, freeCodeCamp doesn’t realise that you’ve actually used two spaces. However, note that you don’t actually need to make sure that the separators are both the same type of whitespace, just that they both are whitespace – so you could just do /^(\d+)\s\1\s\d+$/. That should pass all the tests.

But be warned, your Regular Expression isn’t correct. It’ll pass the tests, but your final \d+ should instead still be a reference to your capturing group (\1). For example, with your regular expression, 42 42 52 would pass; but instead it should fail. Good luck!

2 Likes

I think it’s not possible, because RegExps can only match regular languages. I also asked some of my friends, they couldn’t figure it out. I asked in the fCC gitter room, and nobody figured it out within a few hours.

The reason why this isn’t possible is that you can’t refer to a capturing group before something has been captured. That means you can’t say {not a \1}(\d+)\s\1\s\1.

I tried some combinations after posting here. Like /^(\d+) \1 \1$/.
But didn’t work either.
The one you said here worked just fine.
Thank you very much.

1 Like

Try this, if you’re stuck

let repeatNum = “42 42 42”;
let reRegex =/^(\d+)\s\1\s\1$/; // Change this line
let result = reRegex.test(repeatNum);

11 Likes

I’ve been trying to figure out the solution to this challenge using Regexr, and this code doesn’t capture anything. I’ve tried it in regex101 and it doesn’t work either. I’m so confused as to why it does work in this challenge… I don’t think I’ve learned anything about how to properly use Regex in the end, I just don’t get it.

But thanks for your code, because I was getting increasingly frustrated by being stuck on not passing ‘42 42 42 42’…

Hey, don’t feel too bad - those lessons are pretty unclear unfortunately, I found they actually made me more confused about what was going on then when I started in places.

The code above does seem to work for me in regex101, what does it show on your screen?

PS.
http://www.rexegg.com has a very good tutorial and reference materials. It might be a bit overwhelming at first though.

1 Like

You’re welcome :slight_smile:

Passed the test but I still don’t understand what are capture groups.

What is a group? And why we need to put /1 after the search pattern?

The capture group just specifies a section of your regular expression that you want to reuse. So instead of a regular expression re = /\d+\s\d+\s\d+/ (which is not quite the solution), you can reuse parts that are repeated with the \1, i.e. re = /(\d+)\s\1\s\1/ where the \1 references the first capturing group (stuff in parenthesis) and gets re-used like a variable.

If you had two different capturing groups in the same regular expression, you would use \1 for the first group and \2 for the second. It’s because an array is created (not starting at zero) behind the scenes.

4 Likes

So what is the difference between the first group and the second group? Is that they are created in different arrays?

i solved it with this - let reRegex = /^(\d{1,})\s\1\s\1$/; but honestly I don’t understand why it worked. I had stuck with this for hours and finally this solution worked… I wish somebody could explain why it worked

Different entries in the same array.
/(\d+)(\s)\1\2/ would be the same as saying /\d+\s\d+\s/ because the \1 repeats the first capture group and \2 repeats the second one.

3 Likes

You could use the + operator on your \d the same as {1,} as they both find 1 or more occurrences of the preceding term.

Verbally, your regex is looking for a string that starts with 1+ digits followed by a space followed by 1+ digits (the \1 is repeating what’s in the first capture group) followed by a space followed by 1+ digits that ends the substring. Thus anything with less than two number groupings or more than three wouldn’t qualify. Hope that helps!

1 Like

for some reason when I use \d+ it does not pass the test whatsoever. I guess some website bug or something. I tried that at first and then just started trying all kind of staff and d{1,} worked