Functional Weave
Code in Python

validation.phone-e164@1.0.0

README.md

3,803 bytes · view raw

# validation.phone-e164

Turns a phone number as someone typed it into E.164, the "+" form every SMS
gateway and telephony API wants, reading national numbers as dialled from a
default country.

## Scope: this is not libphonenumber

It knows twelve countries, and for each only what normalising needs: the
calling code, the trunk prefix dialled inside the country, the international
prefix dialled to leave it, the range of national number lengths, and which
digits a national number may start with. It does not know which ranges are
allocated, whether a number is mobile or fixed, or any country's area codes.
A pass means "plausibly a number in that country", not "a line that rings".
For full numbering-plan validation, use Google's libphonenumber.

Countries: GB, IE, US, CA, FR, DE, ES, IT, NL, AU, NZ, IN. A number in
international form with any other calling code is `unknown-country-code`.

## How a number is read

1. Spaces, hyphens, dots and brackets are ignored. A "+" is allowed only at
   the start. Anything else, including the letters of a vanity number and an
   extension ("ext 12"), is `bad-character`.
2. A number starting with the default country's international prefix is read
   as international: 00 in most of Europe and India, 011 in North America,
   0011 in Australia.
3. In international form the calling code is matched (calling codes are
   prefix-free, so there is only ever one match). Otherwise the default country
   applies, and with no default country the answer is `no-country`.
4. The trunk prefix (0, or 1 in North America) is dropped once if present.
   That handles "07700 900123" and the UK habit of writing "+44 (0)20 ...".
   Spain and Italy have no trunk prefix, and in Italy the leading 0 of a
   landline is part of the number: "06 1234 5678" is +390612345678.
5. The national number's length and first digit are checked against the
   table. North American area codes cannot start with 0 or 1; that is the only
   area-code rule applied.

The US and Canada share +1 and the same rules, so which of them a +1 number
belongs to is not reported: the result carries the calling code, not a country.

| reason | meaning (checked in this order) |
|---|---|
| `empty` | no digits and no "+", or not a string |
| `bad-character` | a character other than digits, separators and a leading "+" |
| `bad-format` | a "+" that is not at the start, or nothing after it |
| `no-country` | a national number and no default country |
| `unknown-country-code` | a calling code outside the table |
| `bad-length` | the national number is too short or too long for the country |
| `bad-prefix` | the national number starts with a digit the country never uses |

An unsupported `defaultCountry` is a programming error and throws
(`unsupported default country "XX"`); "" means international form only.

## Data

`data/phone-countries.json`. The calling codes are ITU-T E.164 assignments;
trunk and international prefixes are those each national regulator publishes.
The lengths are deliberately wide plausibility bounds, not the exact lengths
per range: GB 9-10 (a few areas still have 9-digit national numbers), IE 7-9,
US/CA 10, FR 9, DE 5-13 (German numbers vary in length by area), ES 9, IT
6-11, NL 9, AU 9, NZ 8-10, IN 10. Numbering plans do change; a change is a
new version of this data.

## Sources

- ITU-T Recommendation E.164 and the ITU list of country calling codes
  ("List of ITU-T Recommendation E.164 assigned country codes"):
  https://www.itu.int/pub/T-SP-E.164D
- ITU-T operational bulletin annex, national numbering plans (per country
  trunk and international prefixes): https://www.itu.int/oth/T0202
- Ofcom, drama numbers used in the vectors (07700 900xxx, 020 7946 0xxx):
  https://www.ofcom.org.uk/phones-and-broadband/phone-numbers/numbers-for-drama