969

I'm trying to put together a comprehensive regex to validate phone numbers. Ideally it would handle international formats, but it must handle US formats, including the following:

  • 1-234-567-8901
  • 1-234-567-8901 x1234
  • 1-234-567-8901 ext1234
  • 1 (234) 567-8901
  • 1.234.567.8901
  • 1/234/567/8901
  • 12345678901

I'll answer with my current attempt, but I'm hoping somebody has something better and/or more elegant.

the Tin Man
  • 150,910
  • 39
  • 198
  • 279
Nicholas Trandem
  • 2,795
  • 5
  • 28
  • 32
  • 1
    This answer has been added to the [Stack Overflow Regular Expression FAQ](http://stackoverflow.com/a/22944075/2736496), under "Common Validation Tasks". – aliteralmind Apr 10 '14 at 01:24

42 Answers42

535

Better option... just strip all non-digit characters on input (except 'x' and leading '+' signs), taking care because of the British tendency to write numbers in the non-standard form +44 (0) ... when asked to use the international prefix (in that specific case, you should discard the (0) entirely).

Then, you end up with values like:

 12345678901
 12345678901x1234
 345678901x1234
 12344678901
 12345678901
 12345678901
 12345678901
 +4112345678
 +441234567890

Then when you display, reformat to your hearts content. e.g.

  1 (234) 567-8901
  1 (234) 567-8901 x1234
mwfearnley
  • 2,377
  • 1
  • 27
  • 29
scunliffe
  • 57,883
  • 24
  • 118
  • 156
  • 41
    The formatting code is going to be a waste of time if the numbers are allowed to come from outside the US. – Daniel Earwicker Jul 21 '09 at 12:13
  • @Earwicker - agreed the formatting (if dealing with international #'s) should be smart enough to handle various formats... e.g. (0123) 456 7890 or +1 234 567-89-01. Depending how complex you want to get it should be something that can be figured out based on the number of digits and what the first few digits are. – scunliffe Jul 21 '09 at 13:36
  • 27
    This is good and all, but it doesn't validate what was entered was actually a phone number. For example, what if the user doesn't enter the requisite 10 digits? This should be combined with good regex validation. – Hugh Jeffner Jul 29 '10 at 13:40
  • 3
    string.replace("[^\d+!x]", "") – Joel McBeth Dec 06 '10 at 19:51
  • jcmcbeth, why the `!x` part? This seems to suffice: `[^\d+]` http://www.rubular.com/r/aj32fRSSGK – Danilo Bargen Jan 28 '11 at 22:09
  • 6
    @danilo - The !x is there to keep any "x" character from getting stripped so that extensions can be separated out. – cdeszaq Feb 28 '11 at 16:53
  • 124
    Considering the question was about validation - this is a really really bad answer. – PlexQ Mar 30 '12 at 17:12
  • 17
    @PlexQ I disagree. The original problem is trying to handle phone number validation because it was trying to handle all the possible formatting options. Rather than try to solve all that, take the input and "pre-strip" it of all formatting fluff until you have just the "number". Doing this solves 2 problems - testing the result is now easy and you can now ensure that values rendered back out for display can all be formatted consistently. The first comment on this answer about the "Complicator's Gloves" is a good read... sometimes the answer to a problem is to approach it differently. – scunliffe Mar 30 '12 at 20:19
  • 1
    For others who may be using the above `[^\d+!x]` - the exclamation point is unnecessary. Just use `[^\d+x]`. See http://stackoverflow.com/questions/10340336/why-the-exclamation-point-in-another-stackoverflow-posting-involving-telephone-n. – Dan Nissenbaum Apr 26 '12 at 21:18
  • 2
    @Raymond you can use `$justDigitsOrPlusOrX = preg_replace("/[^\d+x]/", "", $phoneNum);` to strip away all the chars you don't need... then test the remaining (if needed) – scunliffe Jul 04 '12 at 19:21
  • 4
    This works nicely, except in case of numbers like `1-800-CALL-NOW`? – Swanand Feb 15 '13 at 06:40
  • 2
    @Swanand I suppose in those scenarios if that's what you really wanted you could enable a smart translation that would convert the letters to their matching numbers... but I think that's a very special corner case compared to what most folks are after. ;-) – scunliffe Feb 15 '13 at 14:32
  • 4
    Improvement on Regex above: `/[^\d+x]|x(?=[^x]*x)/gi` Prevents multiple x's (uses the last x in the string) – Albert Bori May 13 '13 at 20:37
  • 3
    This is nice, but it does not answer the posed question that explicitly requests a RegEx solution. – Kehlan Krumme Aug 09 '13 at 17:53
  • 1
    @nashwan did you read the article linked in the first comment added by Nicholas Trandem the Original Question Poster? Sometimes (as you can see how the community has voted) even though there is a solution to use a 261 character regex that handles a bunch of scenarios... trying to attack the problem in a different manner is actually the answer you want. Note Dave Kirby's answer also suggests not using a strict regex... also gaining (ATM 79 upvotes) – scunliffe Aug 27 '13 at 21:10
  • @Swanand It's cute when people spell things out in the letter mappings that are on most phone keypads, but it's not encouraged in the standards. http://tools.ietf.org/html/rfc3966#section-5.1.2 – ekillaby Oct 17 '13 at 02:12
  • 1
    You can't just allow anything and then strip out what you don't want if you plan to format later. You need something you can format later. – Jack Holt Nov 26 '13 at 16:39
  • 1
    I should clarify that I would "store" the clean value, and only "decorate" it as needed for display later on. – scunliffe Nov 26 '13 at 19:43
  • 2
    You do need to be careful when presented with an number starting `+44 (0)` as well. This is a very common format in the UK, and you probably want to map it to `+44` (i.e. remove the `(0)`). – alastair Apr 01 '14 at 11:19
  • 4
    Yeah, validating or formatting phone numbers is not a good idea. The following are all valid German phone numbers: +49 (0) 89 12345, +49 (0)6221 1234. If you're in Germany, you'd dial those as 089 12345 or 06221 1234, but from e.g. Switzerland it'd be 0049 89 12345 or 0049 6221 1234. So this is like the UK case, but our area codes don't have a fixed length. Unless you have a list, you can't format the numbers correctly. – uliwitness Apr 01 '14 at 13:03
  • 34
    How the hell is this such a highly voted answer? This doesn't _validate_ anything. What's worse is all the other phone number validation questions reference this one... – jlars62 Jun 19 '14 at 18:37
  • 6
    @jlars62 it may not validate a phone number, but it offers an alternate solution that is more reliable than trying to divine whether a given phone number is valid - considering that the idea of valid differs significantly between countries. IMO it's a good solution, while I agree it doesn't validate it still solves the problem. – totallyNotLizards Jun 26 '14 at 15:41
  • @configurator Well, country dialing codes have the prefix property, so your example (4 (420) 778-457800) if 4 is the country code and 420 is an area/city code) could not be a real number, however your point that the "+" is important to designate whether the first number(s) are a country code stands -- maybe a better example would be – Peyton Jul 04 '14 at 17:36
  • This works but adds a layer of complexity to the logic. – JohnMerlino Aug 15 '14 at 18:32
  • 4
    Does not use regular expressions. +1 – John Shedletsky May 01 '15 at 01:25
  • See also : https://technet.microsoft.com/en-us/library/cc728034(v=ws.10).aspx If using TAPI to dial on windows this may help. – Ben Sep 08 '15 at 09:31
  • I created a [public gist](https://gist.github.com/jhabdas/66abcf1ac862179cf4bf) providing an ES6 function building on the regex @AlbertBori provided. Feedback welcomed. – Josh Habdas Jan 09 '16 at 23:24
  • 1
    UK numbers (+44) should have 10 digits after the 0/+44. e.g. 01234 567 890 – mwfearnley Mar 10 '16 at 10:46
  • @mwfearnley Not all there are ones with 9 and 7 (also freephone ones with 9 and 7) https://en.wikipedia.org/wiki/Telephone_numbers_in_the_United_Kingdom and in living memory the length has changed – mmmmmm Mar 21 '16 at 22:00
  • I stand corrected.. I'm old enough to remember the change - I used to live in 0234 :) – mwfearnley Mar 22 '16 at 22:06
  • I muse: "because of the British tendency to write numbers in the non-standard form +44 (0)" If its a tendency of a lot of people, is this not a standard then? (and bloody annoying, even if I do it myself). – Jmons May 02 '17 at 18:06
  • 2
    how could this be validated as the best answer honestly – fdsfdsfdsfds Dec 11 '17 at 09:26
  • 2
    Not acceptable, what if you don't control the input ? it doesn't address the question. – Leo Gurdian Jan 26 '18 at 23:33
  • 2
    This is a great answer. It's showing that you should convert to an integer, then validate *that* (presumably using a simple algorithm). That part is implied, or at least seems obvious to me. Validating a phone number with a regex on the fly is insane. Besides... what is there to validate in the first place? That it's a real phone number? Why? If the user provides a bad phone number, that's their problem. – user428517 Apr 17 '18 at 21:23
  • 1
    this does not answer the question at all. about the only thing this answer gives is to normalize your input. that is not what was asked. why is this the accepted answer? – RisingSun Jan 28 '20 at 17:18
316

It turns out that there's something of a spec for this, at least for North America, called the NANP.

You need to specify exactly what you want. What are legal delimiters? Spaces, dashes, and periods? No delimiter allowed? Can one mix delimiters (e.g., +0.111-222.3333)? How are extensions (e.g., 111-222-3333 x 44444) going to be handled? What about special numbers, like 911? Is the area code going to be optional or required?

Here's a regex for a 7 or 10 digit number, with extensions allowed, delimiters are spaces, dashes, or periods:

^(?:(?:\+?1\s*(?:[.-]\s*)?)?(?:\(\s*([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9])\s*\)|([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]))\s*(?:[.-]\s*)?)?([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2})\s*(?:[.-]\s*)?([0-9]{4})(?:\s*(?:#|x\.?|ext\.?|extension)\s*(\d+))?$
Justin R.
  • 21,845
  • 21
  • 102
  • 147
  • 7
    here it is without the extension section (I make my users enter ext in a separate field): ^(?:(?:\+?1\s*(?:[.-]\s*)?)?(?:\(\s*([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9])\s*\)|([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]))\s*(?:[.-]\s*)?)?([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2})\s*(?:[.-]\s*)?([0-9]{4})$ – aarona May 04 '10 at 04:37
  • This worked nicely for me. I needed to update the extension part though by adding a slash before the #, otherwise it says from there over is a comment – Brian Surowiec Aug 20 '10 at 16:58
  • What about adding "(" and ")" to that list of delimiters? – Jeremy Ricketts Sep 01 '10 at 03:23
  • 19
    Here is a version that only matches 10 digit phone numbers (not 7 digit like 843-1212): `/(?:(?:\+?1\s*(?:[.-]\s*)?)?(?:(\s*([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9])\s*)|([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]))\s*(?:[.-]\s*)?)([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2})\s*(?:[.-]\s*)?([0-9]{4})/` – Brian Armstrong Sep 07 '10 at 19:32
  • 10
    10 digit accepts () around area code, and dosen't allow preceeding 1 as country code `(?:(?:(\s*\(?([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9])\s*)|([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]))\)?\s*(?:[.-]\s*)?)([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2})\s*(?:[.-]\s*)?([0-9]{4})` – Brooke. Jan 09 '11 at 05:09
  • 5
    @StevenSoroka I have had Jeffrey Friedl's book beside me on my desk for the past two years, as regular expressions are a major part of my work. It takes a good while to really understand regular expressions. Sometimes, the readers of this site are simply looking for an existing soltuion, rather than writing their own, especially in domains with lots of corner cases, such as phone number representations. – Justin R. Mar 28 '13 at 21:06
  • 7
    @fatcat1111 I understand that, but majority of the responses here are "me too" type of one-off regular expressions that likely don't fit any of your corner cases. These then end up on all the websites I'm trying to use and I can't enter my zip code or phone number or email address because someone used a half-baked regular-expression (eg: + is a valid character in email addresses). The best responses on this page point users to libraries, not to napkin-scrawled regexes. – Steven Soroka Apr 05 '13 at 21:49
  • 4
    Be careful to check for non-breaking spaces when copying these expressions. – Nate Glenn Dec 17 '15 at 02:47
  • 1
    I wonder if something changed since you first posted this. It doesn't match at least one valid area code: 410 (Maryland). 410 is [mentioned](https://en.wikipedia.org/wiki/North_American_Numbering_Plan#Modern_plan) in the Wikipedia article you linked to, but 410 has been in service [since 1991](https://en.wikipedia.org/wiki/Area_codes_410%2C_443%2C_and_667). – ThisSuitIsBlackNot May 16 '16 at 22:13
  • 1
    This seems to work with every scenario I put in.. I even put an invalid area code, for example an area code that starts with 1 is invalid and it caught it. AAA+++ Perfection for USA Phone Numbers.. – Switch Apr 16 '19 at 15:44
  • An example of where this regex fails: `866-411-1234` (because it does not allow a 411 exchange per NANPA rules, but these are okay on 8xx numbers). https://regex101.com/r/3DSYIr/1 – drew010 Mar 09 '20 at 21:37
310
.*

If the users want to give you their phone numbers, then trust them to get it right. If they do not want to give it to you then forcing them to enter a valid number will either send them to a competitor's site or make them enter a random string that fits your regex. I might even be tempted to look up the number of a premium rate horoscope hotline and enter that instead.

I would also consider any of the following as valid entries on a web site:

"123 456 7890 until 6pm, then 098 765 4321"  
"123 456 7890 or try my mobile on 098 765 4321"  
"ex-directory - mind your own business"
Kobi
  • 125,267
  • 41
  • 244
  • 277
Dave Kirby
  • 429
  • 1
  • 4
  • 2
  • 215
    I agree with the sentiment here, but sometimes it's nice to perform validation when the phone number is actually going to be used for something important *in the interest of the user*. Best example here is credit card authorization for a purchase. If the phone number is wrong, the auth might fail. – Pointy Nov 10 '10 at 18:21
  • 55
    If the user doesn't want to enter his phone number you can just allow the field to be optional, but is it to much to ask the user to enter a valid phone number if they are going to enter one? – Joel McBeth Dec 06 '10 at 19:41
  • 13
    Also a role of validation is simply to remind people to add area codes etc that they might not otherwise remember to add, but which cannot possibly be guessed after the fact. – Ben McIntyre Feb 23 '11 at 00:09
  • 5
    @Pointy: Yes, but even if it's a valid number, that doesn't mean it's an existing number, and even if it's existing, that doesn't mean that it is the users'. If it's that important, you need to set up an automated system that phones them up to check... If your budget stretches that far :) – Benjol Mar 01 '11 at 12:14
  • 1
    @Benjol yes that's true - my personal feeling here is probably affected by the fact that one of my laptops has a sticky "5" key :-) – Pointy Mar 01 '11 at 12:52
  • 2
    I agree from a usability perspective, but allowing arbitrary input may expose your website to cross-site scripting (XSS) attacks. A malicious user might be able to inject JavaScript in your free-form phone number string. – Chris Peterson Apr 01 '11 at 22:37
  • Sometimes users have to give a valid phone number. If you state that it's part of the ToS to give one, they can't give a fake one without being in violation. If you at least make sure from a validation perspective that what they gave is syntactically correct, it will save a lot of headaches. – PlexQ Mar 30 '12 at 17:14
  • 1
    I usually tend to gravitate towards this way of thinking with user experience. A valid US phone number at the core is 10 digits: `^(.*\d.*){10,}$`. That allows it to be entered in any way the user would like. Then, on the backend, strip out invalid characters. – Cory Mawhorter Sep 28 '12 at 19:35
  • 33
    @Pointy But regex validation won't help you. The one and the only way to actually validate if the phone number is correct is to actually send a message to it (in case of mobile) AND make sure the user confirms using some kind of verification code. This is what you do when the number correctness is important. Everything else is just for user's convenience to protect against some (but not all) typos and does not validate anything. – Alex B Nov 16 '12 at 06:40
  • 1
    @AlexB well sure, I understand that, but if you can help me catch the error of leaving off a digit, it saves me the (slight) inconvenience of getting a server-side error, interpreting it, finding the field again, etc. – Pointy Nov 16 '12 at 13:42
  • 2
    There are a million use cases where this plain text solution is the answer. But there are a million use cases where this would cause many many problems. Look at how you are using the phone number and why you are asking for it. Then you can decide which methodology is right for you. If you don't know why you are asking or how you are using it, you probably shouldn't be asking for a phone number in the first place. – Jason Jan 22 '13 at 19:33
  • True, but then you could just do something along the lines of 'when is not empty, validate'. Something like `if (!empty($telephone) && !validation_function($telephone)) { //throw_error }` then you can choose NOT to input your number. –  Sep 03 '13 at 14:38
  • 15
    Cool. My phone number is _1' OR 1=1 -- PWNED_. See http://xkcd.com/327/ and https://www.owasp.org/index.php/Testing_for_SQL_Injection_(OWASP-DV-005) – Aaron Newton Sep 19 '13 at 08:31
  • 4
    The answer contains the deepest wisdom. – Ziggy Jan 08 '14 at 14:15
  • In my case, I needed to validate the phone number since it was the easiest way to find who was spamming the form. The spammers were the ones using invalid phone numbers. Plus, it was a inquiry form, so we were planning on calling all the people who filled it out, and phone number was a required field. – Evan Donovan Jan 24 '14 at 17:05
  • @EvanDonovan Then you will miss my entry as I will use a dummy phone unless I want you to call me which is very unlikely – mmmmmm Apr 10 '14 at 11:49
  • @Mark: I'm not too concerned about that. Obviously I can't capture everything with a regex. In this case, the spammers were not putting any valid data into the form, whereas I am presuming that if you were filling out the form, you would at least be putting in a valid email. – Evan Donovan Apr 11 '14 at 15:15
  • 7
    This answer does not answer the question - rather it just promotes intolerance of forms, which is *already inherent in us all.* – darkheartfelt Jan 07 '15 at 23:09
  • 3
    @AaronNewton: performing validation at the form level or using regexes is unsafe anyway, there are better ways to prevent sql injection. – Willem Van Onsem Feb 18 '15 at 17:21
  • 1
    @CommuSoft that's completely true. However, a better statement might be _don't rely solely on regex for prevention of SQL injection_. I would still argue that it makes sense to check for obviously wrong or nefarious input, e.g. can you think of a case where a phone number needs anything other than alpha-numerics + basic punctuation, or needs to be longer than the length of the field in the database? Regarding the latter, it is likely to confuse and or annoy the user if the database field is 128 characters but you allow the user to enter 129 characters, resulting in some error on the UI. – Aaron Newton Feb 19 '15 at 01:17
  • 4
    This response is irreverent and in no way relevant to the question. The OP asked for help validating the format of input from a user; not for your personal opinion about whether he should. Potential use case: The website is for a company's internal usage - not meaning intranet usage, but rather this company has employees that work "out in the field" and communicate with in-office employees via this website. They need the person to enter a valid phone number at which they can be reached, as part of their job requirements, and want to avoid simple mistakes that could cause headaches. – Mike Manard Jul 23 '15 at 22:31
  • .* is a regex which will validate zero or more characters of any type as valid, which misses the goal of phone number validation. – lee Oct 13 '15 at 19:15
  • Of course that doesn't take into account forms that do require a phone number. I'm currently building an app to keep track of licensing information within our organization. Vendor phone numbers are required so I'd certainly like to validate them. – DrewB Oct 12 '16 at 12:14
  • 3
    If you want to *truly* validate a phone number... **PHONE IT!!** This is just like the ridiculous regular expressions people have come up with to "validate an email address"... If you really care that the email address is valid, then **SEND THEM AN EMAIL!!** – Tom Lord Oct 26 '16 at 09:23
  • -1 because you can make the field NOT required and still need to validate it to help prevent accidental misspells. The part of the answer with 'or try my mobile on' is just rubbish IMO. You give the format its user decision to follow it or not. Just dont make it required thats all. – Unicorn Dec 16 '16 at 01:37
  • 2
    Question was not about user input validation. Could be validating a list of aggregated phone numbers from multiple systems, collected at different times via different forms. Dirty data comes from all sorts of places. – Yarin Nov 09 '17 at 18:46
  • I think you made a mistake. This is not hard way to get the correct number from the user because, as you mentioned, the user can eventually escape and enter another person's number. It is a validation of the number to classify the information so that we have clean information in the future without any additional information and extra chars from the user, for operation possible future use. – Nabi K.A.Z. Feb 24 '19 at 13:14
  • The merits of the OP's question isn't the question to be answered. I'm only leaving this comment because SO asked me to, but now is complaining the reference to my vote. – Altimus Prime Nov 29 '19 at 03:49
185

I would also suggest looking at the "libphonenumber" Google Library. I know it is not regex but it does exactly what you want.

For example, it will recognize that:

15555555555

is a possible number but not a valid number. It also supports countries outside the US.

Highlights of functionality:

  • Parsing/formatting/validating phone numbers for all countries/regions of the world.
  • getNumberType - gets the type of the number based on the number itself; able to distinguish Fixed-line, Mobile, Toll-free, Premium Rate, Shared Cost, VoIP and Personal Numbers (whenever feasible).
  • isNumberMatch - gets a confidence level on whether two numbers could be the same.
  • getExampleNumber/getExampleNumberByType - provides valid example numbers for all countries/regions, with the option of specifying which type of example phone number is needed.
  • isPossibleNumber - quickly guessing whether a number is a possible phonenumber by using only the length information, much faster than a full validation.
  • isValidNumber - full validation of a phone number for a region using length and prefix information.
  • AsYouTypeFormatter - formats phone numbers on-the-fly when users enter each digit.
  • findNumbers - finds numbers in text input.
  • PhoneNumberOfflineGeocoder - provides geographical information related to a phone number.

Examples

The biggest problem with phone number validation is it is very culturally dependant.

  • America
    • (408) 974–2042 is a valid US number
    • (999) 974–2042 is not a valid US number
  • Australia
    • 0404 999 999 is a valid Australian number
    • (02) 9999 9999 is also a valid Australian number
    • (09) 9999 9999 is not a valid Australian number

A regular expression is fine for checking the format of a phone number, but it's not really going to be able to check the validity of a phone number.

I would suggest skipping a simple regular expression to test your phone number against, and using a library such as Google's libphonenumber (link to GitHub project).

Introducing libphonenumber!

Using one of your more complex examples, 1-234-567-8901 x1234, you get the following data out of libphonenumber (link to online demo):

Validation Results

Result from isPossibleNumber()  true
Result from isValidNumber()     true

Formatting Results:

E164 format                    +12345678901
Original format                (234) 567-8901 ext. 123
National format                (234) 567-8901 ext. 123
International format           +1 234-567-8901 ext. 123
Out-of-country format from US  1 (234) 567-8901 ext. 123
Out-of-country format from CH  00 1 234-567-8901 ext. 123

So not only do you learn if the phone number is valid (which it is), but you also get consistent phone number formatting in your locale.

As a bonus, libphonenumber has a number of datasets to check the validity of phone numbers, as well, so checking a number such as +61299999999 (the international version of (02) 9999 9999) returns as a valid number with formatting:

Validation Results

Result from isPossibleNumber()  true
Result from isValidNumber()     true

Formatting Results

E164 format                    +61299999999
Original format                61 2 9999 9999
National format                (02) 9999 9999
International format           +61 2 9999 9999
Out-of-country format from US  011 61 2 9999 9999
Out-of-country format from CH  00 61 2 9999 9999

libphonenumber also gives you many additional benefits, such as grabbing the location that the phone number is detected as being, and also getting the time zone information from the phone number:

PhoneNumberOfflineGeocoder Results
Location        Australia

PhoneNumberToTimeZonesMapper Results
Time zone(s)    [Australia/Sydney]

But the invalid Australian phone number ((09) 9999 9999) returns that it is not a valid phone number.

Validation Results

Result from isPossibleNumber()  true
Result from isValidNumber()     false

Google's version has code for Java and Javascript, but people have also implemented libraries for other languages that use the Google i18n phone number dataset:

Unless you are certain that you are always going to be accepting numbers from one locale, and they are always going to be in one format, I would heavily suggest not writing your own code for this, and using libphonenumber for validating and displaying phone numbers.

Dennis
  • 46,786
  • 25
  • 128
  • 129
Halfwarr
  • 7,397
  • 6
  • 29
  • 50
  • Noting that there is now also Go port at: https://github.com/ttacon/libphonenumber – michaelhanson Sep 12 '16 at 18:59
  • When checking if it's a possible number don't you need to specify a country code? I'm using the PHP version and if I enter a British number like (replace 0's with real numbers) `07700000000` I get `Missing or invalid default region.` error. But if I specify the country code it will pass. – BugHunterUK Nov 28 '16 at 23:22
  • FYI : This library does not support some countries, http://phpinterviewquestions.co.in/blog/ionic/googles-libphonenumber-library-supported-country-list – sijo vijayan Jul 22 '17 at 08:26
  • 2
    @BugHunterUK (and anyone who comes across this question and wonders the same) when parsing a number, you can specify the expected region, and the library will look for non-international numbers in that region. If you don't specify, it will reject anything not in a valid international format. – IMSoP Mar 22 '18 at 16:56
  • Consider https://github.com/nyaruka/phonenumbers as it has become the "official" Go package recommended by Google rather than libphonenumber. – DeeZone May 06 '19 at 14:59
  • I can confirm what @BugHunterUK says. Took time to get there, but the result is exactly as expected - local numbers accepted in any format plus all fully specified international formats. – dimplex Jul 09 '20 at 07:43
83

/^(?:(?:\(?(?:00|\+)([1-4]\d\d|[1-9]\d?)\)?)?[\-\.\ \\\/]?)?((?:\(?\d{1,}\)?[\-\.\ \\\/]?){0,})(?:[\-\.\ \\\/]?(?:#|ext\.?|extension|x)[\-\.\ \\\/]?(\d+))?$/i

This matches:

 - (+351) 282 43 50 50
 - 90191919908
 - 555-8909
 - 001 6867684
 - 001 6867684x1
 - 1 (234) 567-8901
 - 1-234-567-8901 x1234
 - 1-234-567-8901 ext1234
 - 1-234 567.89/01 ext.1234
 - 1(234)5678901x1234
 - (123)8575973
 - (0055)(123)8575973

On $n, it saves:

  1. Country indicator
  2. Phone number
  3. Extension

You can test it on https://www.regexpal.com/?fam=99127

Richard Parnaby-King
  • 13,858
  • 11
  • 64
  • 123
Ismael Miguel
  • 3,941
  • 1
  • 27
  • 35
  • This was the most comprehensive regex I've seen. It's easy to get around until you remove `^` and `$` or else I'm able to get around it using `[111] [111] [1111]` or `111--111--1111` and the like. (sorry, deleted my last comment) – bafromca Mar 07 '14 at 20:10
  • Can you please re-phrase? I can't understand this: "It's easy to get arround until you remove ^ and $ or else I'm able to get around it using [111] [111] [1111]". Does it mean that it validates '[111] [111] [1111]' when you take the `^` and the `$`? – Ismael Miguel Mar 07 '14 at 20:13
  • I got around your regex using `[111] [111] [1111]` and `111--111--1111` until I removed `^` and `$` from the regex. – bafromca Mar 07 '14 at 20:15
  • As I asked before, which engine are you using? `111-111-1111` validates perfectly (syntactically, the second one is valid) while `[111] [111] [1111]` doesn't validate (as expected) – Ismael Miguel Mar 07 '14 at 20:18
  • http://www.gethifi.com/tools/regex and I meant `111--111--1111` as mentioned above. – bafromca Mar 07 '14 at 20:21
  • `111--111--1111` is invalid: http://i62.tinypic.com/2rnhr7k.png (perfectly fine) and `[111] [111] [1111]` is also invalid: http://i58.tinypic.com/9ru64y.png (as expected) – Ismael Miguel Mar 07 '14 at 20:25
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/49273/discussion-between-bafromca-and-ismael-miguel) – bafromca Mar 07 '14 at 21:57
  • 13
    ^^^This is a great example of why comment threads should NOT go to chat. I am very interested in how this conversation turned out and need to know if this ReGex is sturdy enough to use in my app. Unfortunately, the chat conversation is now gone. – Matt Cashatt Jul 18 '14 at 16:53
  • 2
    To be honest, i didnt went to chat. After asking multiple times for explainations, i was left with no info. You can always try it yourself with all kind of numbers you find online, in multiple formats. One thing i tried with this one is to use multiple phone numbers, but it doesnt work that well if they have spaces around. And i have to find a solution to count the amount of digits and enforce a specific amount. – Ismael Miguel Jul 19 '14 at 18:09
  • How do I make this so it can extract the number from a string, anywhere that the phone number may be? – Kousha Feb 17 '17 at 00:29
  • @Kousha Remove the `^` and the `$`, and it should work with lots of false positives. – Ismael Miguel Feb 17 '17 at 00:31
  • @Kousha That's expected. You're trying to make a Javascript RegExp work on PHP with PCRE. You need to slightly re-write it. Which is outside the scope of this question. Using https://regex101.com/, pasting the regex there and going to "tools" -> "code generator", you get this: `/(?:(?:\(?(?:00|\+)([1-4]\d\d|[1-9]\d?)\)?)?[\-\.\ \\\\\/]?)?((?:\(?\d{1,}\)?[\-\.\ \\\\\/]?){0,})(?:[\-\.\ \\\\\/]?(?:#|ext\.?|extension|x)[\-\.\ \\\\\/]?(\d+))?/i`. And this one works. – Ismael Miguel Feb 17 '17 at 01:18
63

Although the answer to strip all whitespace is neat, it doesn't really solve the problem that's posed, which is to find a regex. Take, for instance, my test script that downloads a web page and extracts all phone numbers using the regex. Since you'd need a regex anyway, you might as well have the regex do all the work. I came up with this:

1?\W*([2-9][0-8][0-9])\W*([2-9][0-9]{2})\W*([0-9]{4})(\se?x?t?(\d*))?

Here's a perl script to test it. When you match, $1 contains the area code, $2 and $3 contain the phone number, and $5 contains the extension. My test script downloads a file from the internet and prints all the phone numbers in it.

#!/usr/bin/perl

my $us_phone_regex =
        '1?\W*([2-9][0-8][0-9])\W*([2-9][0-9]{2})\W*([0-9]{4})(\se?x?t?(\d*))?';


my @tests =
(
"1-234-567-8901",
"1-234-567-8901 x1234",
"1-234-567-8901 ext1234",
"1 (234) 567-8901",
"1.234.567.8901",
"1/234/567/8901",
"12345678901",
"not a phone number"
);

foreach my $num (@tests)
{
        if( $num =~ m/$us_phone_regex/ )
        {
                print "match [$1-$2-$3]\n" if not defined $4;
                print "match [$1-$2-$3 $5]\n" if defined $4;
        }
        else
        {
                print "no match [$num]\n";
        }
}

#
# Extract all phone numbers from an arbitrary file.
#
my $external_filename =
        'http://web.textfiles.com/ezines/PHREAKSANDGEEKS/PnG-spring05.txt';
my @external_file = `curl $external_filename`;
foreach my $line (@external_file)
{
        if( $line =~ m/$us_phone_regex/ )
        {
                print "match $1 $2 $3\n";
        }
}

Edit:

You can change \W* to \s*\W?\s* in the regex to tighten it up a bit. I wasn't thinking of the regex in terms of, say, validating user input on a form when I wrote it, but this change makes it possible to use the regex for that purpose.

'1?\s*\W?\s*([2-9][0-8][0-9])\s*\W?\s*([2-9][0-9]{2})\s*\W?\s*([0-9]{4})(\se?x?t?(\d*))?';
indiv
  • 15,860
  • 6
  • 52
  • 82
  • 2
    FYI the regex also matches: `(4570457-6789` which would be a pretty common typo. The match groups get skewed too: http://rubular.com/r/TaTP0mHL5c – SooDesuNe Feb 20 '13 at 19:16
  • @SooDesuNe Prepending `(^|[^\d\n])` (with multiline flag on) avoids the general problem, by ensuring it's not immediately preceded by something numeric. – btown Mar 23 '17 at 19:32
  • Note that this is North America-centric -- it misses "44 7911 123456" – Ben Wheeler Mar 25 '20 at 16:40
51

I answered this question on another SO question before deciding to also include my answer as an answer on this thread, because no one was addressing how to require/not require items, just handing out regexs: Regex working wrong, matching unexpected things

From my post on that site, I've created a quick guide to assist anyone with making their own regex for their own desired phone number format, which I will caveat (like I did on the other site) that if you are too restrictive, you may not get the desired results, and there is no "one size fits all" solution to accepting all possible phone numbers in the world - only what you decide to accept as your format of choice. Use at your own risk.

Quick cheat sheet

  • Start the expression: /^
  • If you want to require a space, use: [\s] or \s
  • If you want to require parenthesis, use: [(] and [)] . Using \( and \) is ugly and can make things confusing.
  • If you want anything to be optional, put a ? after it
  • If you want a hyphen, just type - or [-] . If you do not put it first or last in a series of other characters, though, you may need to escape it: \-
  • If you want to accept different choices in a slot, put brackets around the options: [-.\s] will require a hyphen, period, or space. A question mark after the last bracket will make all of those optional for that slot.
  • \d{3} : Requires a 3-digit number: 000-999. Shorthand for [0-9][0-9][0-9].
  • [2-9] : Requires a digit 2-9 for that slot.
  • (\+|1\s)? : Accept a "plus" or a 1 and a space (pipe character, |, is "or"), and make it optional. The "plus" sign must be escaped.
  • If you want specific numbers to match a slot, enter them: [246] will require a 2, 4, or 6. (?:77|78) or [77|78] will require 77 or 78.
  • $/ : End the expression
vapcguy
  • 5,607
  • 1
  • 45
  • 43
  • 1
    This is very useful, but I doubt and looking for a {min,max} expression. Can you help? – Ataboy Josef Jan 07 '15 at 08:02
  • If it is a single digit we're talking about (and you can make it match according to that), see the `[2-9]` block I put there. That means your min is 2, and your max is 9. Adjust accordingly. – vapcguy Jan 07 '15 at 21:00
33

I wrote simpliest (although i didn't need dot in it).

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

As mentioned below, it checks only for characters, not its structure/order

Artjom Kurapov
  • 5,975
  • 3
  • 29
  • 42
  • 40
    this validates tons of numbers that are technically invalid. like, "-- +()()())())))". Learn to read regular expressions so you can understand what you're doing. – Steven Soroka Mar 28 '13 at 14:47
  • 3
    @StevenSoroka technically it may allow lot of invalid cases, but when we think about just helping the user out to avoid common mistakes with the simplest possible solution, this is the way to go :) – happyhardik Aug 23 '13 at 18:44
  • 2
    this also matching white space, empty line – Wasim A. Sep 16 '13 at 08:13
  • 1
    @HappyHardik. Indeed. Simple and powerful, for basic validation let the user type more than one dot, dash, bracket or plus. – dijipiji Feb 04 '14 at 12:18
  • 1
    Just used it and it's wrong in many aspects. For example, a UK phone number may begin with +44, or a phone nuber may have (0) inside it. But this is not valid according to your regular expression. I would recommend @Ismael Miguel's answer. It works just fine and I would recommend you to revise your answer. – Stelios Voskos Jul 29 '15 at 10:44
23

Note that stripping () characters does not work for a style of writing UK numbers that is common: +44 (0) 1234 567890 which means dial either the international number:
+441234567890
or in the UK dial 01234567890

shA.t
  • 15,232
  • 5
  • 47
  • 95
Ben Clifford
  • 1,348
  • 1
  • 12
  • 20
22

If you just want to verify you don't have random garbage in the field (i.e., from form spammers) this regex should do nicely:

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

Note that it doesn't have any special rules for how many digits, or what numbers are valid in those digits, it just verifies that only digits, parenthesis, dashes, plus, space, pound, asterisk, period, comma, or the letters e, x, t are present.

It should be compatible with international numbers and localization formats. Do you foresee any need to allow square, curly, or angled brackets for some regions? (currently they aren't included).

If you want to maintain per digit rules (such as in US Area Codes and Prefixes (exchange codes) must fall in the range of 200-999) well, good luck to you. Maintaining a complex rule-set which could be outdated at any point in the future by any country in the world does not sound fun.

And while stripping all/most non-numeric characters may work well on the server side (especially if you are planning on passing these values to a dialer), you may not want to thrash the user's input during validation, particularly if you want them to make corrections in another field.

the Tin Man
  • 150,910
  • 39
  • 198
  • 279
Steve
  • 106
  • 1
  • 5
15

Have you had a look over at RegExLib?

Entering US phone number brought back quite a list of possibilities.

Rob Wells
  • 34,617
  • 13
  • 76
  • 144
  • 3
    This looks like a great way to integrate obscure bugs into your code. – Tom Lord Oct 26 '16 at 09:25
  • Link-only answers should be avoided because they may break in the future and render the post useless. Static solutions are always necessary to sustain the value of an answer. If you wanted to recommend a hyperlink, add it as a comment under the question. – mickmackusa Jul 31 '20 at 20:24
14

My attempt at an unrestrictive regex:

/^[+#*\(\)\[\]]*([0-9][ ext+-pw#*\(\)\[\]]*){6,45}$/

Accepts:

+(01) 123 (456) 789 ext555
123456
*44 123-456-789 [321]
123456
123456789012345678901234567890123456789012345
*****++[](][((( 123456tteexxttppww

Rejects:

mob 07777 777777
1234 567 890 after 5pm
john smith
(empty)
1234567890123456789012345678901234567890123456
911

It is up to you to sanitize it for display. After validating it could be a number though.

Lajos Arpad
  • 45,912
  • 26
  • 82
  • 148
ReactiveRaven
  • 5,853
  • 2
  • 28
  • 38
12

Here's a wonderful pattern that most closely matched the validation that I needed to achieve. I'm not the original author, but I think it's well worth sharing as I found this problem to be very complex and without a concise or widely useful answer.

The following regex will catch widely used number and character combinations in a variety of global phone number formats:

/^\s*(?:\+?(\d{1,3}))?([-. (]*(\d{3})[-. )]*)?((\d{3})[-. ]*(\d{2,4})(?:[-.x ]*(\d+))?)\s*$/gm

Positive:
+42 555.123.4567
+1-(800)-123-4567
+7 555 1234567
+7(926)1234567
(926) 1234567
+79261234567
926 1234567
9261234567
1234567
123-4567
123-89-01
495 1234567
469 123 45 67
89261234567
8 (926) 1234567
926.123.4567
415-555-1234
650-555-2345
(416)555-3456
202 555 4567
4035555678
1 416 555 9292

Negative:
926 3 4
8 800 600-APPLE

Original source: http://www.regexr.com/38pvb

Stuart Kershaw
  • 13,825
  • 5
  • 35
  • 47
12

I found this to work quite well:

^\(*\+*[1-9]{0,3}\)*-*[1-9]{0,3}[-. /]*\(*[2-9]\d{2}\)*[-. /]*\d{3}[-. /]*\d{4} *e*x*t*\.* *\d{0,4}$

It works for these number formats:

1-234-567-8901
1-234-567-8901 x1234
1-234-567-8901 ext1234
1 (234) 567-8901
1.234.567.8901
1/234/567/8901
12345678901
1-234-567-8901 ext. 1234
(+351) 282 433 5050

Make sure to use global AND multiline flags to make sure.

Link: http://www.regexr.com/3bp4b

11

Here's my best try so far. It handles the formats above but I'm sure I'm missing some other possible formats.

^\d?(?:(?:[\+]?(?:[\d]{1,3}(?:[ ]+|[\-.])))?[(]?(?:[\d]{3})[\-/)]?(?:[ ]+)?)?(?:[a-zA-Z2-9][a-zA-Z0-9 \-.]{6,})(?:(?:[ ]+|[xX]|(i:ext[\.]?)){1,2}(?:[\d]{1,5}))?$
Nicholas Trandem
  • 2,795
  • 5
  • 28
  • 32
11

If you're talking about form validation, the regexp to validate correct meaning as well as correct data is going to be extremely complex because of varying country and provider standards. It will also be hard to keep up to date.

I interpret the question as looking for a broadly valid pattern, which may not be internally consistent - for example having a valid set of numbers, but not validating that the trunk-line, exchange, etc. to the valid pattern for the country code prefix.

North America is straightforward, and for international I prefer to use an 'idiomatic' pattern which covers the ways in which people specify and remember their numbers:

^((((\(\d{3}\))|(\d{3}-))\d{3}-\d{4})|(\+?\d{2}((-| )\d{1,8}){1,5}))(( x| ext)\d{1,5}){0,1}$

The North American pattern makes sure that if one parenthesis is included both are. The international accounts for an optional initial '+' and country code. After that, you're in the idiom. Valid matches would be:

  • (xxx)xxx-xxxx
  • (xxx)-xxx-xxxx
  • (xxx)xxx-xxxx x123
  • 12 1234 123 1 x1111
  • 12 12 12 12 12
  • 12 1 1234 123456 x12345
  • +12 1234 1234
  • +12 12 12 1234
  • +12 1234 5678
  • +12 12345678

This may be biased as my experience is limited to North America, Europe and a small bit of Asia.

the Tin Man
  • 150,910
  • 39
  • 198
  • 279
ron0
  • 61
  • 1
  • 4
  • I've been trying to implement the above in my javascript validation script but I keep getting an `invalid quantifier` error. Any ideas on what I'm doing wrong? – Jannis Oct 17 '10 at 20:07
  • I'd add the trivial case where the phone is specified without symbols but maybe spaces and country code, in Europe is typical for local and mobile numbers: 676412342, 676 46 32 12, 676 463 212 – rupps Apr 19 '15 at 23:12
10

My gut feeling is reinforced by the amount of replies to this topic - that there is a virtually infinite number of solutions to this problem, none of which are going to be elegant.

Honestly, I would recommend you don't try to validate phone numbers. Even if you could write a big, hairy validator that would allow all the different legitimate formats, it would end up allowing pretty much anything even remotely resembling a phone number in the first place.

In my opinion, the most elegant solution is to validate a minimum length, nothing more.

mindplay.dk
  • 6,381
  • 2
  • 39
  • 48
  • After trying a number of these and going through the existing data and feedback from users i would tend to agree... – Christopher King Jan 17 '14 at 15:12
  • Sometimes you need to do validation though. If I'm sending out confirmation codes I can't just send a code to any random garbage a spammer has input in the field. I want to make sure the number is *probably* a phone number before wasting resources messaging it. – zfj3ub94rf576hc4eegm Apr 24 '20 at 10:29
10

This is a simple Regular Expression pattern for Philippine Mobile Phone Numbers:

((\+[0-9]{2})|0)[.\- ]?9[0-9]{2}[.\- ]?[0-9]{3}[.\- ]?[0-9]{4}

or

((\+63)|0)[.\- ]?9[0-9]{2}[.\- ]?[0-9]{3}[.\- ]?[0-9]{4}

will match these:

+63.917.123.4567  
+63-917-123-4567  
+63 917 123 4567  
+639171234567  
09171234567  

The first one will match ANY two digit country code, while the second one will match the Philippine country code exclusively.

Test it here: http://refiddle.com/1ox

the Tin Man
  • 150,910
  • 39
  • 198
  • 279
GaiusSensei
  • 1,846
  • 4
  • 25
  • 44
  • Thanks. How about landline numbers with area code such as 028231234? I'm wondering if area codes are only 2-3 digit numbers and are they always preceded by 0? – stormwild Feb 26 '14 at 05:41
9

You'll have a hard time dealing with international numbers with a single/simple regex, see this post on the difficulties of international (and even north american) phone numbers.

You'll want to parse the first few digits to determine what the country code is, then act differently based on the country.

Beyond that - the list you gave does not include another common US format - leaving off the initial 1. Most cell phones in the US don't require it, and it'll start to baffle the younger generation unless they've dialed internationally.

You've correctly identified that it's a tricky problem...

-Adam

Community
  • 1
  • 1
Adam Davis
  • 87,598
  • 55
  • 254
  • 328
  • Not an offered solution. IT IS POSSIBLE. Just because it's tricky or complex doesn't mean you should just throw your arms up. – Eric Hodonsky Mar 29 '17 at 16:14
7

After reading through these answers, it looks like there wasn't a straightforward regular expression that can parse through a bunch of text and pull out phone numbers in any format (including international with and without the plus sign).

Here's what I used for a client project recently, where we had to convert all phone numbers in any format to tel: links.

So far, it's been working with everything they've thrown at it, but if errors come up, I'll update this answer.

Regex:

/(\+*\d{1,})*([ |\(])*(\d{3})[^\d]*(\d{3})[^\d]*(\d{4})/

PHP function to replace all phone numbers with tel: links (in case anyone is curious):

function phoneToTel($number) {
    $return = preg_replace('/(\+*\d{1,})*([ |\(])*(\d{3})[^\d]*(\d{3})[^\d]*(\d{4})/', '<a href="tel:$1$3$4$5">$1 ($3) $4-$5</a>', $number); // includes international
    return $return;
}
Drew Thomas
  • 147
  • 2
  • 9
6

I believe the Number::Phone::US and Regexp::Common (particularly the source of Regexp::Common::URI::RFC2806) Perl modules could help.

The question should probably be specified in a bit more detail to explain the purpose of validating the numbers. For instance, 911 is a valid number in the US, but 911x isn't for any value of x. That's so that the phone company can calculate when you are done dialing. There are several variations on this issue. But your regex doesn't check the area code portion, so that doesn't seem to be a concern.

Like validating email addresses, even if you have a valid result you can't know if it's assigned to someone until you try it.

If you are trying to validate user input, why not normalize the result and be done with it? If the user puts in a number you can't recognize as a valid number, either save it as inputted or strip out undailable characters. The Number::Phone::Normalize Perl module could be a source of inspiration.

Jon Ericson
  • 19,534
  • 11
  • 93
  • 140
  • I'm going to go out on a limb here and say that allowing 911 as a phone number is probably a bad idea in almost all applications of this regex. Good catch though. – Nicholas Flynt Jul 10 '12 at 20:29
4

Do a replace on formatting characters, then check the remaining for phone validity. In PHP,

 $replace = array( ' ', '-', '/', '(', ')', ',', '.' ); //etc; as needed
 preg_match( '/1?[0-9]{10}((ext|x)[0-9]{1,4})?/i', str_replace( $replace, '', $phone_num );

Breaking a complex regexp like this can be just as effective, but much more simple.

rooskie
  • 484
  • 3
  • 8
4

I work for a market research company and we have to filter these types of input alllll the time. You're complicating it too much. Just strip the non-alphanumeric chars, and see if there's an extension.

For further analysis you can subscribe to one of many providers that will give you access to a database of valid numbers as well as tell you if they're landlines or mobiles, disconnected, etc. It costs money.

Joe Phillips
  • 44,686
  • 25
  • 93
  • 148
  • Validation? 123%$)*%()$*()#456*()*$#(*(#$@8908 would match your proposed solution. – PlexQ Mar 30 '12 at 17:17
  • 1
    @PlexQ 555-123-1234, 07777777777, 90210, 01/01/1901 - users are inventive in ramming garbage through validation. Better to not tic off the ones who genuinely do have some odd data by using overly restrictive validation and telling them they're wrong. – ReactiveRaven Apr 29 '12 at 03:19
3

Here's one that works well in JavaScript. It's in a string because that's what the Dojo widget was expecting.

It matches a 10 digit North America NANP number with optional extension. Spaces, dashes and periods are accepted delimiters.

"^(\\(?\\d\\d\\d\\)?)( |-|\\.)?\\d\\d\\d( |-|\\.)?\\d{4,4}(( |-|\\.)?[ext\\.]+ ?\\d+)?$"
Richard Ayotte
  • 4,671
  • 1
  • 30
  • 33
3

I was struggling with the same issue, trying to make my application future proof, but these guys got me going in the right direction. I'm not actually checking the number itself to see if it works or not, I'm just trying to make sure that a series of numbers was entered that may or may not have an extension.

Worst case scenario if the user had to pull an unformatted number from the XML file, they would still just type the numbers into the phone's numberpad 012345678x5, no real reason to keep it pretty. That kind of RegEx would come out something like this for me:

\d+ ?\w{0,9} ?\d+
  • 01234467 extension 123456
  • 01234567x123456
  • 01234567890
the Tin Man
  • 150,910
  • 39
  • 198
  • 279
3

I found this to be something interesting. I have not tested it but it looks as if it would work

<?php
/*
string validate_telephone_number (string $number, array $formats)
*/

function validate_telephone_number($number, $formats)
{
$format = trim(ereg_replace("[0-9]", "#", $number));

return (in_array($format, $formats)) ? true : false;
}

/* Usage Examples */

// List of possible formats: You can add new formats or modify the existing ones

$formats = array('###-###-####', '####-###-###',
                 '(###) ###-###', '####-####-####',
                 '##-###-####-####', '####-####', '###-###-###',
                 '#####-###-###', '##########');

$number = '08008-555-555';

if(validate_telephone_number($number, $formats))
{
echo $number.' is a valid phone number.';
}

echo "<br />";

$number = '123-555-555';

if(validate_telephone_number($number, $formats))
{
echo $number.' is a valid phone number.';
}

echo "<br />";

$number = '1800-1234-5678';

if(validate_telephone_number($number, $formats))
{
echo $number.' is a valid phone number.';
}

echo "<br />";

$number = '(800) 555-123';

if(validate_telephone_number($number, $formats))
{
echo $number.' is a valid phone number.';
}

echo "<br />";

$number = '1234567890';

if(validate_telephone_number($number, $formats))
{
echo $number.' is a valid phone number.';
}
?>
Bill the Lizard
  • 369,957
  • 201
  • 546
  • 842
Chris
  • 11
  • 1
3

You would probably be better off using a Masked Input for this. That way users can ONLY enter numbers and you can format however you see fit. I'm not sure if this is for a web application, but if it is there is a very click jQuery plugin that offers some options for doing this.

http://digitalbush.com/projects/masked-input-plugin/

They even go over how to mask phone number inputs in their tutorial.

Abe Miessler
  • 75,910
  • 89
  • 276
  • 451
2

My inclination is to agree that stripping non-digits and just accepting what's there is best. Maybe to ensure at least a couple digits are present, although that does prohibit something like an alphabetic phone number "ASK-JAKE" for example.

A couple simple perl expressions might be:

@f = /(\d+)/g;
tr/0-9//dc;

Use the first one to keep the digit groups together, which may give formatting clues. Use the second one to trivially toss all non-digits.

Is it a worry that there may need to be a pause and then more keys entered? Or something like 555-1212 (wait for the beep) 123?

piCookie
  • 8,912
  • 2
  • 17
  • 19
2
    pattern="^[\d|\+|\(]+[\)|\d|\s|-]*[\d]$" 
    validateat="onsubmit"

Must end with a digit, can begin with ( or + or a digit, and may contain + - ( or )

Ian
  • 11
  • 1
2

For anyone interested in doing something similar with Irish mobile phone numbers, here's a straightforward way of accomplishing it:

http://ilovenicii.com/?p=87

PHP


<?php
$pattern = "/^(083|086|085|086|087)\d{7}$/";
$phone = "087343266";

if (preg_match($pattern,$phone)) echo "Match";
else echo "Not match";

There is also a JQuery solution on that link.

EDIT:

jQuery solution:

    $(function(){
    //original field values
    var field_values = {
            //id        :  value
            'url'       : 'url',
            'yourname'  : 'yourname',
            'email'     : 'email',
            'phone'     : 'phone'
    };

        var url =$("input#url").val();
        var yourname =$("input#yourname").val();
        var email =$("input#email").val();
        var phone =$("input#phone").val();


    //inputfocus
    $('input#url').inputfocus({ value: field_values['url'] });
    $('input#yourname').inputfocus({ value: field_values['yourname'] });
    $('input#email').inputfocus({ value: field_values['email'] }); 
    $('input#phone').inputfocus({ value: field_values['phone'] });



    //reset progress bar
    $('#progress').css('width','0');
    $('#progress_text').html('0% Complete');

    //first_step
    $('form').submit(function(){ return false; });
    $('#submit_first').click(function(){
        //remove classes
        $('#first_step input').removeClass('error').removeClass('valid');

        //ckeck if inputs aren't empty
        var fields = $('#first_step input[type=text]');
        var error = 0;
        fields.each(function(){
            var value = $(this).val();
            if( value.length<12 || value==field_values[$(this).attr('id')] ) {
                $(this).addClass('error');
                $(this).effect("shake", { times:3 }, 50);

                error++;
            } else {
                $(this).addClass('valid');
            }
        });        

        if(!error) {
            if( $('#password').val() != $('#cpassword').val() ) {
                    $('#first_step input[type=password]').each(function(){
                        $(this).removeClass('valid').addClass('error');
                        $(this).effect("shake", { times:3 }, 50);
                    });

                    return false;
            } else {   
                //update progress bar
                $('#progress_text').html('33% Complete');
                $('#progress').css('width','113px');

                //slide steps
                $('#first_step').slideUp();
                $('#second_step').slideDown();     
            }               
        } else return false;
    });

    //second section
    $('#submit_second').click(function(){
        //remove classes
        $('#second_step input').removeClass('error').removeClass('valid');

        var emailPattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;  
        var fields = $('#second_step input[type=text]');
        var error = 0;
        fields.each(function(){
            var value = $(this).val();
            if( value.length<1 || value==field_values[$(this).attr('id')] || ( $(this).attr('id')=='email' && !emailPattern.test(value) ) ) {
                $(this).addClass('error');
                $(this).effect("shake", { times:3 }, 50);

                error++;
            } else {
                $(this).addClass('valid');
            }


        function validatePhone(phone) {
        var a = document.getElementById(phone).value;
        var filter = /^[0-9-+]+$/;
            if (filter.test(a)) {
                return true;
            }
            else {
                return false;
            }
        }

        $('#phone').blur(function(e) {
            if (validatePhone('txtPhone')) {
                $('#spnPhoneStatus').html('Valid');
                $('#spnPhoneStatus').css('color', 'green');
            }
            else {
                $('#spnPhoneStatus').html('Invalid');
            $('#spnPhoneStatus').css('color', 'red');
            }
        });

     });

        if(!error) {
                //update progress bar
                $('#progress_text').html('66% Complete');
                $('#progress').css('width','226px');

                //slide steps
                $('#second_step').slideUp();
                $('#fourth_step').slideDown();     
        } else return false;

    });


    $('#submit_second').click(function(){
        //update progress bar
        $('#progress_text').html('100% Complete');
        $('#progress').css('width','339px');

        //prepare the fourth step
        var fields = new Array(
            $('#url').val(),
            $('#yourname').val(),
            $('#email').val(),
            $('#phone').val()

        );
        var tr = $('#fourth_step tr');
        tr.each(function(){
            //alert( fields[$(this).index()] )
            $(this).children('td:nth-child(2)').html(fields[$(this).index()]);
        });

        //slide steps
        $('#third_step').slideUp();
        $('#fourth_step').slideDown();            
    });


    $('#submit_fourth').click(function(){

        url =$("input#url").val();
        yourname =$("input#yourname").val();
        email =$("input#email").val();
        phone =$("input#phone").val();

        //send information to server
        var dataString = 'url='+ url + '&yourname=' + yourname + '&email=' + email + '&phone=' + phone;  



        alert (dataString);//return false;  
            $.ajax({  
                type: "POST",  
                url: "http://clients.socialnetworkingsolutions.com/infobox/contact/",  
                data: "url="+url+"&yourname="+yourname+"&email="+email+'&phone=' + phone,
                cache: false,
                success: function(data) {  
                    console.log("form submitted");
                    alert("success");
                }
                });  
        return false;

   });


    //back button
    $('.back').click(function(){
        var container = $(this).parent('div'),
        previous  = container.prev();

        switch(previous.attr('id')) {
            case 'first_step' : $('#progress_text').html('0% Complete');
                  $('#progress').css('width','0px');
                       break;
            case 'second_step': $('#progress_text').html('33% Complete');
                  $('#progress').css('width','113px');
                       break;

            case 'third_step' : $('#progress_text').html('66% Complete');
                  $('#progress').css('width','226px');
                       break;

        default: break;
    }

    $(container).slideUp();
    $(previous).slideDown();
});


});

Source.

Lajos Arpad
  • 45,912
  • 26
  • 82
  • 148
Bob-ob
  • 1,434
  • 4
  • 18
  • 34
1

I wouldn't recomend using a regex for this.

Like the top answer, strip all the ugliness from the phone number, so that you're left with a string of numeric characters, with an 'x', if extensions are provided.

In Python:

Note: BAD_AREA_CODES comes from a text file that you can grab from on the web.

BAD_AREA_CODES = open('badareacodes.txt', 'r').read().split('\n')

def is_valid_phone(phone_number, country_code='US'):
    """for now, only US codes are handled"""
    if country_code:
        country_code = country_code.upper()

    #drop everything except 0-9 and 'x'
    phone_number = filter(lambda n: n.isdigit() or n == 'x', phone_number)

    ext = None
    check_ext = phone_number.split('x')
    if len(check_ext) > 1:
        #there's an extension. Check for errors.
        if len(check_ext) > 2:
            return False
        phone_number, ext = check_ext

    #we only accept 10 digit phone numbers.
    if len(phone_number) == 11 and phone_number[0] == '1':
        #international code
        phone_number = phone_number[1:]
    if len(phone_number) != 10:
        return False

    #area_code: XXXxxxxxxx 
    #head:      xxxXXXxxxx
    #tail:      xxxxxxXXXX
    area_code = phone_number[ :3]
    head      = phone_number[3:6]
    tail      = phone_number[6: ]

    if area_code in BAD_AREA_CODES:
        return False
    if head[0] == '1':
        return False
    if head[1:] == '11':
        return False

    #any other ideas?
    return True

This covers quite a bit. It's not a regex, but it does map to other languages pretty easily.

Droogans
  • 6,701
  • 5
  • 36
  • 60
1

If at all possible, I would recommend to have four separate fields—Area Code, 3-digit prefix, 4 digit part, extension—so that the user can input each part of the address separately, and you can verify each piece individually. That way you can not only make verification much easier, you can store your phone numbers in a more consistent format in the database.

Cody Gray
  • 222,280
  • 47
  • 466
  • 543
Kibbee
  • 62,900
  • 26
  • 139
  • 178
  • However, if you decide to go this route, keep in mind that this will not work outside the US. No way to enter a country extension, and e.g. Germany has variable-length area codes (anywhere from 2-4 digits, plus a leading zero if you're dialing from within Germany, which is left out if you have a country code before it). – uliwitness Apr 01 '14 at 13:12
1

Working example for Turkey, just change the

d{9}

according to your needs and start using it.

function validateMobile($phone)
{
    $pattern = "/^(05)\d{9}$/";
    if (!preg_match($pattern, $phone))
    {
        return false;
    }
    return true;
}

$phone = "0532486061";

if(!validateMobile($phone))
{
    echo 'Incorrect Mobile Number!';
}

$phone = "05324860614";
if(validateMobile($phone))
{
    echo 'Correct Mobile Number!';
}
Sinan Eldem
  • 4,712
  • 2
  • 32
  • 35
1

It's near to impossible to handle all sorts of international phone numbers using simple regex.

You'd be better off using a service like numverify.com, they're offering a free JSON API for international phone number validation, plus you'll get some useful details on country, location, carrier and line type with every request.

Frank
  • 584
  • 1
  • 7
  • 30
1

Find String regex = "^\\+(?:[0-9] ?){6,14}[0-9]$";

helpful for international numbers.

Sai prateek
  • 10,642
  • 8
  • 39
  • 60
1

As there is no language tag with this post, I'm gonna give a regex solution used within python.

The expression itself:

1[\s./-]?\(?[\d]+\)?[\s./-]?[\d]+[-/.]?[\d]+\s?[\d]+

When used within python:

import re

phonelist ="1-234-567-8901,1-234-567-8901 1234,1-234-567-8901 1234,1 (234) 567-8901,1.234.567.8901,1/234/567/8901,12345678901"

phonenumber = '\n'.join([phone for phone in re.findall(r'1[\s./-]?\(?[\d]+\)?[\s./-]?[\d]+[-/.]?[\d]+\s?[\d]+' ,phonelist)])
print(phonenumber)

Output:

1-234-567-8901
1-234-567-8901 1234
1-234-567-8901 1234
1 (234) 567-8901
1.234.567.8901
1/234/567/8901
12345678901
SIM
  • 20,216
  • 3
  • 27
  • 78
1

Although it's not regex, you can use the function validate_phone() from the Python library DataPrep to validate US phone numbers. Install it with pip install dataprep.

>>> from dataprep.clean import validate_phone
>>> df = pd.DataFrame({'phone': ['1-234-567-8901', '1-234-567-8901 x1234', 
         '1-234-567-8901 ext1234', '1 (234) 567-8901', '1.234.567.8901',
         '1/234/567/8901', 12345678901, '12345678', '123-456-78987']})
>>> validate_phone(df['phone'])
0     True
1     True
2     True
3     True
4     True
5     True
6     True
7    False
8    False
Name: phone, dtype: bool
victoria55
  • 173
  • 1
  • 5
0

Note It takes as an input a US mobile number in any format and optionally accepts a second parameter - set true if you want the output mobile number formatted to look pretty. If the number provided is not a mobile number, it simple returns false. If a mobile number IS detected, it returns the entire sanitized number instead of true.

    function isValidMobile(num,format) {
        if (!format) format=false
        var m1 = /^(\W|^)[(]{0,1}\d{3}[)]{0,1}[.]{0,1}[\s-]{0,1}\d{3}[\s-]{0,1}[\s.]{0,1}\d{4}(\W|$)/
        if(!m1.test(num)) {
           return false
        }
        num = num.replace(/ /g,'').replace(/\./g,'').replace(/-/g,'').replace(/\(/g,'').replace(/\)/g,'').replace(/\[/g,'').replace(/\]/g,'').replace(/\+/g,'').replace(/\~/g,'').replace(/\{/g,'').replace(/\*/g,'').replace(/\}/g,'')
        if ((num.length < 10) || (num.length > 11) || (num.substring(0,1)=='0') || (num.substring(1,1)=='0') || ((num.length==10)&&(num.substring(0,1)=='1'))||((num.length==11)&&(num.substring(0,1)!='1'))) return false;
        num = (num.length == 11) ? num : ('1' + num);   
        if ((num.length == 11) && (num.substring(0,1) == "1")) {
            if (format===true) {
               return '(' + num.substr(1,3) + ') ' + num.substr(4,3) + '-' + num.substr(7,4)
            } else {
               return num
            }
        } else {
            return false;
        }
    }
Gautam Sharma
  • 196
  • 2
  • 11
0

Try this (It is for Indian mobile number validation):

if (!phoneNumber.matches("^[6-9]\\d{9}$")) {
  return false;
} else {
  return true;
}
Shailendra Madda
  • 16,925
  • 14
  • 71
  • 115
0

Java generates REGEX for valid phone numbers

Another alternative is to let Java generate a REGEX that macthes all variations of phone numbers read from a list. This means that the list called validPhoneNumbersFormat, seen below in code context, is deciding which phone number format is valid.

Note: This type of algorithm would work for any language handling regular expressions.

Code snippet that generates the REGEX:

Set<String> regexSet = uniqueValidPhoneNumbersFormats.stream()
        .map(s -> s.replaceAll("\\+", "\\\\+"))
        .map(s -> s.replaceAll("\\d", "\\\\d"))
        .map(s -> s.replaceAll("\\.", "\\\\."))
        .map(s -> s.replaceAll("([\\(\\)])", "\\\\$1"))
        .collect(Collectors.toSet());

String regex = String.join("|", regexSet);

Code snippet in context:

public class TestBench {

    public static void main(String[] args) {
        List<String> validPhoneNumbersFormat = Arrays.asList(
                "1-234-567-8901",
                "1-234-567-8901 x1234",
                "1-234-567-8901 ext1234",
                "1 (234) 567-8901",
                "1.234.567.8901",
                "1/234/567/8901",
                "12345678901",
                "+12345678901",
                "(234) 567-8901 ext. 123",
                "+1 234-567-8901 ext. 123",
                "1 (234) 567-8901 ext. 123",
                "00 1 234-567-8901 ext. 123",
                "+210-998-234-01234",
                "210-998-234-01234",
                "+21099823401234",
                "+210-(998)-(234)-(01234)",
                "(+351) 282 43 50 50",
                "90191919908",
                "555-8909",
                "001 6867684",
                "001 6867684x1",
                "1 (234) 567-8901",
                "1-234-567-8901 x1234",
                "1-234-567-8901 ext1234",
                "1-234 567.89/01 ext.1234",
                "1(234)5678901x1234",
                "(123)8575973",
                "(0055)(123)8575973"
        );

        Set<String> uniqueValidPhoneNumbersFormats = new LinkedHashSet<>(validPhoneNumbersFormat);

        List<String> invalidPhoneNumbers = Arrays.asList(
                "+210-99A-234-01234",       // FAIL
                "+210-999-234-0\"\"234",    // FAIL
                "+210-999-234-02;4",        // FAIL
                "-210+998-234-01234",       // FAIL
                "+210-998)-(234-(01234"     // FAIL
        );
        List<String> invalidAndValidPhoneNumbers = new ArrayList<>();
        invalidAndValidPhoneNumbers.addAll(invalidPhoneNumbers);
        invalidAndValidPhoneNumbers.addAll(uniqueValidPhoneNumbersFormats);

        Set<String> regexSet = uniqueValidPhoneNumbersFormats.stream()
                .map(s -> s.replaceAll("\\+", "\\\\+"))
                .map(s -> s.replaceAll("\\d", "\\\\d"))
                .map(s -> s.replaceAll("\\.", "\\\\."))
                .map(s -> s.replaceAll("([\\(\\)])", "\\\\$1"))
                .collect(Collectors.toSet());

        String regex = String.join("|", regexSet);

        List<String> result = new ArrayList<>();
        Pattern pattern = Pattern.compile(regex);
        for (String phoneNumber : invalidAndValidPhoneNumbers) {
            Matcher matcher = pattern.matcher(phoneNumber);
            if(matcher.matches()) {
                result.add(matcher.group());
            }
        }

        // Output:
        if(uniqueValidPhoneNumbersFormats.size() == result.size()) {
            System.out.println("All valid numbers was matched!\n");
        }    
        result.forEach(System.out::println); 
    }

}

Output:

All valid numbers was matched!

1-234-567-8901
1-234-567-8901 x1234
1-234-567-8901 ext1234
...
...
...
DigitShifter
  • 481
  • 3
  • 7
-2

since there are so many options to write a phone number, one can just test that are enough digits in it, no matter how they are separated. i found 9 to 14 digits work for me:

^\D*(\d\D*){9,14}$

true:

  • 123456789
  • 1234567890123
  • +123 (456) 78.90-98.76

false:

  • 123
  • (1234) 1234
  • 9007199254740991
  • 123 wont do what you tell me
  • +123 (456) 78.90-98.76 #543 ext 210>2>5>3
  • (123) 456-7890 in the morning (987) 54-3210 after 18:00 and ask for Shirley

if you do want to support those last two examples - just remove the upper limit:

(\d\D*){9,}

(the ^$ are not needed if there's no upper limit)

oriadam
  • 5,404
  • 2
  • 35
  • 39
-4
/\b(\d{3}[^\d]{0,2}\d{3}[^\d]{0,2}\d{4})\b/
bcherny
  • 2,714
  • 1
  • 22
  • 30