If you only support US numbers, you could simply format the digits to show parenthesis and x wherever you want.
I would prefer to store the whole string, I would parse it using a regex to validate it, then store it in a normalized string.
To make it accept any country, I would do this:
I would add the IDD code to all phone numbers, and then hide it from users from that country.
so: (123) 456-7890 x1234 would be stored as +1 (123) 456-7890 x1234
The (perl-compatible) regex would be something like (completely untested and wouldn't work) :
(+\d+)?\s+(((\d{,3}))(?\s+([-.0-9]{6,})\s+((x|ext\w*)\d{,4})
- This is an optional number of digits preceded by +
- Followed by one or more spaces
- Then an optional group of up to 3 digits between parenthesis
- Then one or more spaces
- Then a group of 6 or more digits, dashes or dots
- Then one or more spaces
- Then an optional x or a word that begins with ext (ext, extension ...) and a group of up to 4 digits
I would have a database of users including country and area code, then fill those in automatically in case they're missing, the country would have it's default digit grouping convention for phone numbers (3,4 for the us).
- So if you're in area 123 in the us, and enter 456.7890, it would be parsed as +1 (123) 4567890, and you would only see it as 456-7890
- if you're in Qatar and enter the number 4444555 extenshn 33, it is stored as +974 4444555 x33, you would see it as 4444555 x33
The international code will not be displayed for users in the same country, and the area code will not be displayed for users in the same country and area code. The full number would be displayed onmouseover (HTML label?)