4

i have this function to check my phone number:

function isValid( $what, $data ) {

        switch( $what ) {

                // validate a phone number
                case 'phone_number':
                        $pattern = "/^[0-9-+]+$/";

                break;



                default:
                        return false;
                break;

        }
        return preg_match($pattern, $data) ? true : false;
}

i want to change that regex to accept the following: the ) ( chars like (800) and the space.

So for example this number will pass the validation, right now is not passing:

+1 (201) 223-3213

Abude
  • 2,112
  • 7
  • 35
  • 58
  • 1
    A word of warning when it comes to phone numbers and regular expressions - it's next to impossible to match generic phone numbers with a regular expression alone (people write them in too many different ways). If you're using it for verification rather than discovery, I recommend stripping out all allowed non-digit characters (`+-()` in this case), including spaces, before testing it. This way you have far better control over the result and you avoid things like your current regex matching obviously incorrect numbers such as `+`, `-`, and `1` (you only require a single character). – Vala Aug 23 '12 at 09:25
  • so you mean remove all the chars from the string and then test and after that format it somehow? can you give me a code example PHP how can i strip all the chars and test? thanks ! – Abude Aug 23 '12 at 09:50
  • 1
    I've added an answer with example code for you. – Vala Aug 23 '12 at 10:39

4 Answers4

8

Let us construct the regular expression step by step. Consider also that spaces are trimmed before matching.

  • at the beginning there might or might not be a + sign. This also needs to be escaped. \+?
  • then comes one or more digits, before the part with parenthesis [0-9]+ You might want to write [0-9]* if the number can begin directly with a group in parenthesis
  • then, optionally comes a group of digits in parenthesis: (\[0-9]+\)?. Suppose that only one such group is allowed
  • then comes the local phone number, hyphens also allowed: [0-9-]*
  • the final character must be a digit [0-9], hyphen is not allowed here

    ^\+?[0-9]+(\([0-9]+\))?[0-9-]*[0-9]$
    

See the result here. Trimming spaces looks like $trimmed = str_replace(' ', '', $pattern);.

Lorlin
  • 844
  • 5
  • 15
  • 1
    +1. The best regex for the requirements here so far, and good breakdown. You are however not dealing with the spaces the OP specifically mentions. This can obviously be easily remedied by adding `\s*` in the relevant locations or stripping all spaces from the string before matching. – Vala Aug 23 '12 at 09:19
  • Great man ! +1 . you really explained to me exactly the steps. appreciate it so much :) – Abude Aug 23 '12 at 09:21
  • and if i want to be like this number `+011 (+66) 115-1221` is this gona work `^\+?[0-9]+(\(\+?[0-9]+\))?[0-9-]*[0-9]$` ? – Abude Aug 23 '12 at 09:46
  • how to add space to your regex ?`\s` ? – Abude Aug 23 '12 at 10:06
  • Exactly. @Thor84no is right about the spaces, however it might be easier to remove them at the beginning so the regexp remain cleaner. E.g. `$trimmed = str_replace(' ', '', $pattern);` http://stackoverflow.com/questions/2109325/how-to-strip-all-spaces-out-of-a-string-in-php – Lorlin Aug 23 '12 at 10:07
  • but how can i add the space to be accepted in your regex rule ? thanks! – Abude Aug 23 '12 at 10:11
  • Someting like this `^\s*\+?\s*([0-9]+\s*)+\s*(\(([0-9]+\s*)+\))?\s*[0-9-\s]*[0-9]\s*$` but it will make hard times for anybody who will maintain the code. – Lorlin Aug 23 '12 at 10:21
  • i doesn't work really with the number `+011 (+66) 115-1221` maybe make the space optional ? thanks for all the guiding ! – Abude Aug 23 '12 at 10:27
  • `\s*` does make the space optional. – Vala Aug 23 '12 at 10:33
  • The plus sign after parenthesis you added is not included in my regexp. – Lorlin Aug 23 '12 at 10:38
  • yes @Thor84no and Lorin perfect ! you were right, but still one thing, the second plus is not in the regex between the `()` ? – Abude Aug 23 '12 at 10:41
  • I'm not sure what you're asking here, but the regex he has provided doesn't allow for a second `+`, the `+` you see in the regex there means "one or more occurrences of the previous group", the previous group being a digit (`[0-9]`). – Vala Aug 23 '12 at 10:45
  • no:), i meant if i have this phone number `+011 (+66) 115-1221` is invalid because the plus in the `(+66)` and need to add the plus to the regex to make it a valid number, do you know what i mean? thanks! – Abude Aug 23 '12 at 10:47
  • i made it like this `^\s*\+?\s*([0-9]+\s*)+\s*(\((\+?[0-9]+\s*)+\))?\s*[0-9-\s]*[0-9]\s*$` i think it's working :) – Abude Aug 23 '12 at 10:53
4

How about this regexp:

/^[0-9-+()\s]+$/

See it in action here

zb226
  • 9,586
  • 6
  • 49
  • 79
  • 2
    Note that this would work, but would also match `1 + 2 - (10 + 30)` ***Edit***: And it would also match just one space, a plus `+`, a dash `-` or just a parenthesis `(`. – h2ooooooo Aug 23 '12 at 08:44
  • @Jimmy Yes. It'd also work with `(((((())))()()((()(+++---` for that sake. – h2ooooooo Aug 23 '12 at 08:54
  • 2
    @h2ooooooo Of course this isn't a perfect phone number validation, but that wasn't the question either. The question was how to make the regex accept round braces and spaces. – zb226 Aug 23 '12 at 08:54
  • 1
    @zb226 I agree - I was actually writing this same Regex. I'm just explaining the OP about the complications that *might* come using it. – h2ooooooo Aug 23 '12 at 08:55
  • Sure, you're technically meeting the OPs requirements, however you're just making his (already unsuitable) regex WORSE. You know what the goal is and this is a terrifyingly bad regex for the job that just gives a false sense of security that only valid phone numbers are accepted. "Valid" phone numbers such as `+(2 - 5)((5 - 3) - 4) - 3`, or any other complete gibberish. At this stage you might as well drop the regex completely, it's not doing any good. – Vala Aug 23 '12 at 09:41
1
'/\(?\b[0-9]{3}\)?[-. ]?[0-9]{3,5}[-. ]?[0-9]{4,8}\b/'
TheHe
  • 2,933
  • 18
  • 22
1

Since you seem to be using this for validation you can use str_replace('[\s\+\-\(\)]', '', $data) to get a string that should (if the phone number is valid) contain only digits. You can then test this assumption easily by running preg_match('\d{11}', $data) (the {11} means 11 digits, if there's a range allowed, use min, max like this {min,max}, e.g. \d{10,11}).

It's worth noting that this isn't as thorough as Lorlin's answer in that you're ignoring any invalid use of brackets, +s or -s. You may want to use a combination of the two, or whatever suits your needs the best.

Vala
  • 5,628
  • 1
  • 29
  • 55
  • you are right about the spaces, but it's ok for me if the code `regex` is that way with optional of spaces although needs some fix :(. thank you very much :) – Abude Aug 23 '12 at 10:45
  • If you go with Lorlin's answer, I would recommend stripping the spaces rather than having them optional in the regex, simply because this makes the regex more readable, and therefore more maintainable. – Vala Aug 23 '12 at 10:49
  • i need your help with the stripping out all the spaces:( can you help me please ? – Abude Aug 24 '12 at 11:26
  • 1
    `str_replace('\s+', '');` This basically means "match one (or more (`+`)) white-space character (`\s`) - space, new line, tab, etc. and replace them with nothing". `str_replace` will do this for every match it finds in the entire string, meaning at the end you'll have no white-space of any kind. – Vala Aug 24 '12 at 12:52