The point is that we use hasMatch method which literally just checks do you have match or not. Or, in other words, does the whole target text has a sequence of symbols that corresponds to the regexp.
Regex1
The first regexp (numbersOnly) ^[0-9]+$ definitely has match for the last test line with 17 numbers 12341234123412345 — all this line contains only digits from start to end — so no surprise that this regexp gives us true.
The second regexp (validLength) .{16} also has a match — our test line 12341234123412345 has 16 + 1 = 17 digits — so this regexp also outputs true (see #1 on the screenshot below).
Regex2
The expression from the second example ([0-9]{16}) acts similarly — it says that the test line 12341234123412345 do has 16 digits: this 16 digits digit sequence is included to 17 digits line — and that regexp also says Yes, I have a match! (see #2 on the screenshot below).
How to validate only 16 numbers?
Just add the start of line and end of line tokens to what you have: ^[0-9]{16}$
(or even shorter ^\d{16}$)
Regular expressions are self-contained stand-alone mini-language and particularly with these simple cases we are talking about it works absolutely the same in any programming language supporting regexps.
I wish I could say this was just a typo, but when I was creating the exercise question, I completely missed the logic of an explicit range regex also matching a longer string because of its substrings. So, yes, adding ^ and $ to match the entire string is a good solution. One benefit of being a writer is having people like you catch my errors. I get to learn, too. Thank you.
This error also affect the text of Chapter 1, “Strings”, so I’ve updated the internal repo to fix that. The online book should reflect that change soon. The new content states the following. Bolded text is new:
final goodLength = RegExp(r'^.{12,}$');
if (!password.contains(goodLength)) {
print('Your password must be at least 12 characters long!');
}
Recall that ^ and $ match the beginning and end of the string. This ensures you’re validating the whole password. The {} curly braces indicate a length range in regex. Using {12} means a length of exactly 12, {12,15} means a length of 12 to 15 characters, and {12,} means a length of at least 12 with no upper limit. Because {12,} follows the . character, you’re allowing 12 or more of any character.
While the original book example still worked in practice, the explanation about {12} and {12,15} would not have worked for the upper limits.