tags:

views:

84

answers:

3

I current have the following regular expression to accept any numeric value that is seven digits

^\d{7}

How do I improve it so it will accept numeric values that are seven or ten digits?

Pass: 0123456, 1234567, 0123456789, 123467890
Fail: 123456, 12345678, 123456789

+5  A: 

A simple solution is this:

^\d{7}(\d{3})?$

There are at least two things to note with this solution:

  • In a unicode context \d may match far more than you intended (for example foreign characters that are digits in other non-Latin languages).
  • This regular expression contains a capturing group. You probably don't want that. You can fix this by changing it to a non-capturing group (?: ... ).

So for these reasons you may want to use this slightly longer expression instead:

^[0-9]{7}(?:[0-9]{3})?$

Here's a little testbed in C# so that you can see it works:

for (int i = 0; i < 12; ++i)
{
    string input = new string('0', i);
    bool isMatch = Regex.IsMatch(input, "^[0-9]{7}(?:[0-9]{3})?$");
    Console.WriteLine(i.ToString().PadLeft(2) + ": " + isMatch);
}

Result:

 0: False
 1: False
 2: False
 3: False
 4: False
 5: False
 6: False
 7: True
 8: False
 9: False
10: True
11: False
Mark Byers
Won't that accept any between 7 and 10 digits?
Michael Mrozek
Sorry I misread the question. Fixed now!
Mark Byers
You're right; it will accept 7 to 10 characters.
Robert P
The regex pattern `^[0-9]{7}(?:[0-9]{3})?$` worked for every scenario
Michael Kniskern
@Michael Kniskern: Great! This question was actually more difficult than it first appeared to be. All three posters initially posted an answer which appeared to be correct but was actually wrong! Even the voters did not notice the errors, upvoting the wrong solutions.
Mark Byers
@Mark. Thanks for your effort. I feel like every time I enter the world of regular expressions, I am playing a dangerous game.
Michael Kniskern
+3  A: 

Edit: This is wrong, but I'm going to undelete it and leave it around for reference purposes, since the upvotes suggest people thought it was right. The correct solution is here


I think just:

^\d{7}\d{3}?
Michael Mrozek
@Mark You mean because it doesn't have a trailing `$`? I left it out because the OP did, but yes, technically :)
Michael Mrozek
Yes, but it matches the original regex's "looseness". :)
Robert P
@Mark It does if you're doing whole-string matching
Michael Mrozek
I want '12345678' to fail. It can only accept numeric values that are 7 or ten digits in length.
Michael Kniskern
All my comments on this post were incorrect so I've deleted them, sorry for the confusion! However I was right that this regular expression is not going to work. I've tested it and it doesn't do what the poster wants, even when taking into account whole-string matching.
Mark Byers
In `\d{3}?` the `?` turns the `{3}` into a reluctant quantifier--in other words, it has no effect. `^\d{7}\d{3}?` matches any string that starts with ten digits.
Alan Moore
+2  A: 

Why not a literal interpretation of what you're looking for:

^\d{7}|\d{10}$
Agent_9191
+1 for readability
Brian Wigginton
Except that won't work quite right either, because that's literally `^\d{7}` or `\d{10}$`. You need to add a a non-capturing group in there, like `^(?:\d{7}|\d{10})$`.
Robert P
+1 for making the machine do the hard work, not me
Bananeweizen