Regular Expression to match UK residential telephone numbers

A regular expression to match UK residential telephone numbers. It understands the difference between 02 and 01 numbers. It will accept all common formats and internationally formatted numbers.

Examples of accepted numbers:

  • 02081234567
  • 0208 123 4567
  • 020 8123 4567
  • 0208 123-4567
  • +44 208 123 4567
  • +44 (0) 208 123 4567
  • 01234 567 890
  • +44 0 1234 567-890
  • 07712 123 456

Examples of numbers that will not be accepted:

  • 020812345678
  • 123456789
  • 07612 123 4567
  • +33 345 876 1298

This is my first submission to the excellent regexlib.com regular expression library – I’d appreciate if you could vote for it!

/^(((44))( )?|((+44))( )?|(+44)( )?|(44)( )?)?((0)|((0)))?( )?(((1[0-9]{3})|(7[1-9]{1}[0-9]{2})|(20)( )?[7-8]{1})( )?([0-9]{3}[ -]?[0-9]{3})|(2[0-9]{2}( )?[0-9]{3}[ -]?[0-9]{4}))$/

Let me know if I’ve missed anything!

Update: This has been amended as per comments below, to allow 020 as a prefix for London, 07624 (Isle of Man) and 074xx xxxxxx.

14 thoughts on “Regular Expression to match UK residential telephone numbers

  1. ** 076 is not a valid prefix. **

    I am sure that people in the Channel islands (07624) will not be very impressed with that.

    Mobile telephones in mainland UK recently started using 075xx too.

    ** 0208 123 4567 **

    There is NO 0208 area code. London is 020. Just 020.

    ** +44 (0) 208 123 4567 **

    The form with (0) in it is NOT valid.

    http://revk.www.me.uk/2009/09/it-is-not-44-0207-123-4567.html

    http://www.itu.int/rec/T-REC-E.123/en

    Local numbers have between 4 and 8 digits. Area code (after zero) can be 2 to 5 digits long. NSN count is 9 or 10 depending on the area.

  2. Hi,

    This is intended to be used for form validation. As such, if we can expect that a user may enter:

    0208 123 4567
    +44 (0) 208 123 4567

    …we should allow those. They are valid, in my opinion, in that people may enter them, and it is trivial to convert these into a standard format for insertion into a database. This was originally written – as you correctly surmised – for mainland UK, and so the Channel islands were not supported. I should amend this though, you are correct, and I shall.

    Thanks for your comment!

  3. The London 020 area code is not the only (02x) area code.

    So far, 023, 024, 028 and 029 are also in use. Those are 02x codes. There are no 02xx area codes.

    The UK number format can be 2+8, 3+7, 4+6, 4+5, 5+5 or 5+4, where the leading 0 ‘trunk code’ is not included in the digit count.

    Ofcom maintain a detailed list of the allocations, published weekly as an Excel spreadsheet.

  4. Can you confirm if the telephone number in the format: 020 8123 4567 is valid using the regex? All of the example accepted numbers work, a part form that format. Thanks

  5. Hi,

    Fantastic regex – it’s flawless for UK residential telephone numbers.

    What about free and local rate business landlines though, such as 0800, 0845 and 0844?

  6. I have recently updated the full list of RegEx patterns for validating and formatting UK telephone numbers. It’s too long to reproduce here and it would be difficult to maintain multiple copies.

    The list can be found at:
    http://www.aa-asterisk.org.uk/index.php/Regular_Expressions_for_Validating_and_Formatting_UK_Telephone_Numbers

    I’m also the UK metadata editor for the Google libphonenumber project over at:
    http://code.google.com/p/libphonenumber/
    The xml metadata file there has number length, validation and formatting information for every country.

  7. 0208 123 4567 is a valid number in London but presented in the wrong format. It should be 020 8123 4567.

    Numbers beginning 020 0 and 020 1 are also allocated in London, and are NDO numbers.

    However, the valid number 020 8123 4567 should be accepted even if entered as 0208 123 4567 or as 02081 234 567 or as 020812 34567 because all the right digits are present.

    The number must then be re-formatted in the correct way for display.

    Users should not be penalised if they enter their number with the right number of digits but in the wrong format.

    —-

    Your pattern:

    ^(((44))( )?|((+44))( )?|(+44)( )?|(44)( )?)?((0)|((0)))?( )?(((1[0-9]{3})|(7[1-9]{1}[0-9]{2})|(20)( )?[7-8]{1})( )?([0-9]{3}[ -]?[0-9]{3})|(2[0-9]{2}( )?[0-9]{3}[ -]?[0-9]{4}))$

    is very inefficient and fails to match many valid UK numbers even when entered in the right format.

    Many of the brackets are redundant.

    —-

    The opening part:

    ^(((44))( )?|((+44))( )?|(+44)( )?|(44)( )?)?((0)|((0)))?( )?

    has a few problems.

    The ((44)) simplifies to (44) for example and ( )? should be s? too.

    The repetition of ’44′ is unecessary. After you’ve found it once, move on!

    The ((44))( )?|((+44))( )? ‘OR’ construct simplifies to (+?44)s? for example, and the (+44)( )?|(44)( )?) ‘OR’ construct simplifies to +?44s? too.

    Both of those then reduce to (?+?44)?s? with optional parentheses and spaces. Don’t insist the user enters balanced parentheses. It’s the digits that matter.

    The opening part simplifies to:

    ^(?+?44)?s?(?|0)

    Yeah, really!

    —-

    If you want to also allow 00 44 and 011 44 (as well as the usual +44 and 0) along with parentheses, spaces and hyphens, try:

    ^(?(?:(?:0(?:0|11))?[s-]?(?|+)44)?[s-]?(?(?:0)?[s-]?(?)?|0)

    for the opening part.

    —-

    The remainder of your pattern:

    (((1[0-9]{3})|(7[1-9]{1}[0-9]{2})|(20)( )?[7-8]{1})( )?([0-9]{3}[ -]?[0-9]{3})|(2[0-9]{2}( )?[0-9]{3}[ -]?[0-9]{4}))$

    doesn’t match all UK formats and has a few syntax issues, discussed below.

    The [1-9]{1} should be just [1-9]. The {1} is redundant.

    The ( )? should be s? here.

    —-

    The ‘London’ part of the pattern:

    (…..|…..|(20)( )?[7-8]{1})( )?([0-9]{3}[ -]?[0-9]{3})|…..)

    is problematical.

    The literal (20) does not need to be in brackets, but isn’t needed at all (see below).

    The [7-8] should be [78] but note that London numbers also begin with 3 now [378].

    Your London pattern fails in other ways too.

    It expects …20 7 XXX XXX or …20 8 XXX XXX which is also a digit short of reality and in a completely incorrect format. London numbers are 2+8 format, not 3+6 or 2+7 or whatever this is.

    There is no need for a London pattern. You need a pattern for all 02 numbers.

    This part (20)( )?[7-8]{1} could be completely removed (read on).

    —-

    Your final chunk of code:

    ((…..|…..|…..)( )?(…..)|(2[0-9]{2}( )?[0-9]{3}[ -]?[0-9]{4}))$

    looks like it should be matching 02 area codes (e.g. 020 8123 4567), but it also has problems.

    02 area codes use the 2+8 format but your pattern expects them to be entered in 3+7 format.

    They should be able to be entered in either format (then corrected to 2+8 format for display).

    —-

    This ‘reduced’ part of the pattern:

    (((1[0-9]{3})|(7[1-9]{1}[0-9]{2})|…..)( )?([0-9]{3}[ -]?[0-9]{3})|(…..))$

    matches 01 and 07 numbers only in 4+6 format.

    It fails to match valid UK 01 numbers in the real 3+7 (e.g. 0116 555 8888 or 0121 555 7777), 4+5 (e.g. 01750 62555), 5+5 (e.g. 015395 77888) and 5+4 (e.g. 016977 3888) formats.

    No UK area codes begin 010, so the first 1[0-9]{3} could be 1[1-9][0-9]{2} if other adjustments were made later in the pattern.

    —-

    Do also consider replacing [0-9] with d for readability; so that character groups are used only for reduced ranges.

    Don’t insist on mandatory brackets, allow them to be optional.

    Don’t insist on ‘balanced’ brackets on user input. As long as the user puts all the right digits in, the brackets really don’t matter.

    Don’t restrict the format the user can use for input. If the user types 015 3957 7888 or 0153 957 7888 or 01539 577888 instead of 015395 77888, let them do that. All the digits are there. Reformat it correctly for display afterwards.

    —-

    Some suggestions

    Use the corrected opening part from above, then match numbers input in 5+4, 5+5, 4+5, 4+6, 3+6, 3+7, 2+8 format:

    (?:d{5})?[s-]?d{4,5}|d{4})?[s-]?(?:d{5}|d{3}[s-]?d{3})|d{3})? [s-]?d{3}[s-]?d{3,4}|d{2})?[s-]?d{4}[s-]?d{4}))

    Putting it all together:

    ^(?(?:(?:0(?:0|11))?[s-]?(?|+)44)?[s-]?(?(?:0)?[s-]?(?)?|0)(?:d{5})?[s-]?d{4,5}|d{4})?[s-]?(?:d{5}|d{3}[s-]?d{3})|d{3})? [s-]?d{3}[s-]?d{3,4}|d{2})?[s-]?d{4}[s-]?d{4}))$

    Once you have matched the input format, extract the 44 country code in $1 (null if national format was used with 0 trunk code) and the NSN in $2 with this:

    ^(?(?:(?:0(?:0|11))?[s-]?(?|+)(44))?[s-]?(?(?:0)?[s-]?(?)?|0)([1-9]d{1,4})?[sd-]+)$

    Clean the extracted NSN of all spaces and punctuation.

    Finally, you can now check the NSN part in more detail.

    Check that the NSN begins ^(1[1-9]|2[03489]|7([457-9]|624)) if you want to restrict the input to landlines (01, 02) and mobile numbers (074, 075, 07624, 077, 078, 079).

    Consider also allowing 03 numbers as these are always charged at the same rate as 01 and 02 numbers: ^(1[1-9]|2[03489]|3[0347]|7([457-9]|624))

    You can make much more detailed checks here if you want. You can even discover the number type by the initial digits.

    This part is much simpler to program now that the dial prefix, country code, trunk prefix and any puncuation clutter has been dumped.

    There’s a very full list of patterns at: http://www.aa-asterisk.org.uk/index.php/Regular_Expressions_for_Validating_and_Formatting_GB_Telephone_Numbers

    RegEx stuff is hard, very hard. I hope these notes are useful.

  8. (revised post, fixes typos)

    0208 123 4567 is a valid number in London but presented in the wrong format. It should be 020 8123 4567.

    Numbers beginning 020 0 and 020 1 are also allocated in London, and are NDO numbers.

    However, the valid number 020 8123 4567 should be accepted even if entered as 0208 123 4567 or as 02081 234 567 or as 020812 34567 because all the right digits are present.

    The number must then be re-formatted in the correct way for display.

    Users should not be penalised if they enter their number with the right number of digits but in the wrong format.

    —-

    Your pattern:

    ^(((44))( )?|((+44))( )?|(+44)( )?|(44)( )?)?((0)|((0)))?( )?(((1[0-9]{3})|(7[1-9]{1}[0-9]{2})|(20)( )?[7-8]{1})( )?([0-9]{3}[ -]?[0-9]{3})|(2[0-9]{2}( )?[0-9]{3}[ -]?[0-9]{4}))$

    is very inefficient and fails to match many valid UK numbers even when entered in the right format.

    Many of the brackets are redundant.

    —-

    The opening part:

    ^(((44))( )?|((+44))( )?|(+44)( )?|(44)( )?)?((0)|((0)))?( )?

    has a few problems.

    The ((44)) simplifies to (44) for example and ( )? should be s? too.

    The repetition of ’44′ is unecessary. After you’ve found it once, move on!

    The 44 and the optional trailing space are common to all four options and should be stated only once.

    The ((44))( )?|((+44))( )? ‘OR’ construct simplifies to (+?44)s? for example.

    The (+44)( )?|(44)( )?) ‘OR’ construct simplifies to +?44s? too.

    Both of those then reduce to (?(+?44)?s?) with optional parentheses and spaces.

    Don’t insist the user enters balanced parentheses. It’s the digits that matter.

    When the user enters a number in international format, the pattern insists on a 0 after the +44. The 0 should not be there, but some people mistakenly type it. You should make the 0 optional, and with optional parentheses.

    Without providing for a 0 after the +44, the opening part simplifies to:

    ^(?(+?44)?s?(?|0)

    which is optional opening parentheses followed by +44 and optional closing parentheses, then optional space and optional opening parentheses, OR initial optional opening parentheses followed by the 0 trunk code.

    With provision for optional parentheses and a 0 after the +44 added back in it becomes:

    ^(?(+?44)?s?(?(0)?s?(?)?|0)

    —-

    If you want to also allow 00 44 and 011 44 (as well as the usual +44 country code and 0 trunk code) along with parentheses, spaces and hyphens, and the optional (0) in optional parentheses after the +44 country code, try:

    ^(?(?:(?:0(?:0|11))?[s-]?(?|+)44)?[s-]?(?(?:0)?[s-]?(?)?|0)

    for the opening part.

    —-

    The remainder of your pattern:

    (((1[0-9]{3})|(7[1-9]{1}[0-9]{2})|(20)( )?[7-8]{1})( )?([0-9]{3}[ -]?[0-9]{3})|(2[0-9]{2}( )?[0-9]{3}[ -]?[0-9]{4}))$

    doesn’t match all UK formats and has a few syntax issues, discussed below.

    The [1-9]{1} should be just [1-9]. The {1} is redundant.

    The ( )? should be s? here.

    —-

    The ‘London’ part of the pattern:

    (…..|…..|(20)( )?[7-8]{1})( )?([0-9]{3}[ -]?[0-9]{3})|…..)

    is problematical.

    The literal (20) does not need to be in brackets, but isn’t needed at all (see below).

    The [7-8] should be [78] but note that London numbers also begin with 3 now [378].

    Your London pattern fails in other ways too.

    It expects …20 7 XXX XXX or …20 8 XXX XXX which is also a digit short of reality and in a completely incorrect format. London numbers are 2+8 format (e.g. 020 3555 7788), not 3+6 or 2+7 or whatever this is.

    There is no need for a London pattern. You need a pattern for all 02 numbers. All 02 numbers use 2+8 format.

    This part (20)( )?[7-8]{1} of your pattern could be completely removed (read on).

    —-

    This part of the pattern for 01 and 07 numbers:

    (((1[0-9]{3})|(7[1-9]{1}[0-9]{2})|…..)( )?([0-9]{3}[ -]?[0-9]{3})|(…..))$

    matches 01 and 07 numbers only in 4+6 format.

    It fails to match valid UK 01 numbers in the real 3+7 (e.g. 0116 555 8888 or 0121 555 7777), 4+5 (e.g. 01750 62555), 5+5 (e.g. 015395 77888) and 5+4 (e.g. 016977 3888) formats.

    No UK area codes begin 010, so the first 1[0-9]{3} could be 1[1-9][0-9]{2} if other adjustments were made later in the pattern, but there’s a better way altogether (discussed at the end).

    Amending the pattern to accept 5+4, 5+5, 4+5, 4+6 and 3+7 format numbers gives this:

    (?:d{5})?[s-]?d{4,5}|d{4})?[s-]?(?:d{5}|d{3}[s-]?d{3})|d{3})?[s-]?d{3}[s-]?d{3,4})

    with provision for optional closing parentheses after the area code followed by optional hyphen or space.

    The new pattern also provides for optional space or hyphen within the subscriber part of the number.

    This part of the new pattern doesn’t care what the leading digit is, so it allows numbers to be entered in the ‘wrong’ format (e.g. 01884 777 888 as 018 8477 7888, 020 3555 7788 as 02035 557 788 and 07788 555777 as 0778 855 5777, etc). Those that are entered in the wrong format should be corrected by a later process.

    —-

    Your final chunk of code:

    ((…..|…..|…..)( )?(…..)|(2[0-9]{2}( )?[0-9]{3}[ -]?[0-9]{4}))$

    looks like it should be matching 02 area codes, but it also has problems.

    02 area codes use the 2+8 format (e.g. 020 8123 4567) but your pattern expects them to be entered in 3+7 format.

    They should be able to be entered in either format (then corrected to 2+8 format for display).

    Here’s the correct pattern for 2+8 format:

    d{2})?[s-]?d{4}[s-]?d{4}

    with provision for optional closing parentheses after the area code followed by optional hyphen or space.

    It also provides for optional space or hyphen within the subscriber part of the number.

    The long pattern in the previous section allows 02 numbers to be entered in 5+5, 4+6 or 3+7 format. If the user does that, the number should be corrected to the right format for display.

    —-

    Do also consider replacing [0-9] with d for readability; so that character groups are used only for reduced ranges.

    Don’t insist on mandatory brackets, allow them to be optional.

    Don’t insist on ‘balanced’ brackets on user input. As long as the user puts all the right digits in, the brackets really don’t matter.

    Don’t restrict the format the user can use for input. If the user types 015 3957 7888 or 0153 957 7888 or 01539 577888 instead of 015395 77888, let them do that. All the digits are there. Reformat it correctly for display afterwards.

    —-

    Your current pattern is this:

    ^(((44))( )?|((+44))( )?|(+44)( )?|(44)( )?)?((0)|((0)))?( )?(((1[0-9]{3})|(7[1-9]{1}[0-9]{2})|(20)( )?[7-8]{1})( )?([0-9]{3}[ -]?[0-9]{3})|(2[0-9]{2}( )?[0-9]{3}[ -]?[0-9]{4}))$

    What your current pattern needs to match, and whether it does:

    016977 3888 [5+4] – no
    017687 55555 [5+5] – no
    01750 62555 [4+5] – no
    0175 062 555 (alt) – no
    0175 062555 (alt) – no
    01884 777 888 [4+6] – yes
    01884 777888 [4+6] – yes
    0116 555 7788 [3+7] – no
    0191 777 8899 [3+7] – no
    020 3555 7788 [2+8] – no
    0203 555 7788 (alt) – yes
    02035 557 788 (alt) – no
    020355 57788 (alt) – no
    024 7555 8899 [2+8] – no
    074557 77888 (alt) – no
    07555 777 888 [4+6] – yes
    07555 777888 [4+6] – yes
    0775 577 7888 (alt) – no
    078 5577 7888 (alt) – no

    (alt) means “alternative spacing that some people might use to enter a number”.

    While spaces are optional in your pattern, most of the parentheses are not but should be.

    Since 03 numbers are charged at the same rate as 01 and 02 numbers, the pattern should also match those.

    —-

    Some suggestions

    Use the corrected opening part from above:

    ^(?(?:(?:0(?:0|11))?[s-]?(?|+)44)?[s-]?(?(?:0)?[s-]?(?)?|0)

    then match numbers input in 5+4, 5+5, 4+5, 4+6, 3+6, 3+7, 2+8 format:

    (?:d{5})?[s-]?d{4,5}|d{4})?[s-]?(?:d{5}|d{3}[s-]?d{3})|d{3})?[s-]?d{3}[s-]?d{3,4}|d{2})?[s-]?d{4}[s-]?d{4})$

    Putting it all together:

    ^(?(?:(?:0(?:0|11))?[s-]?(?|+)44)?[s-]?(?(?:0)?[s-]?(?)?|0)(?:d{5})?[s-]?d{4,5}|d{4})?[s-]?(?:d{5}|d{3}[s-]?d{3})|d{3})?[s-]?d{3}[s-]?d{3,4}|d{2})?[s-]?d{4}[s-]?d{4})$

    Once you have matched the input format, extract the 44 country code in $1 (null if national format was used with 0 trunk code) and the NSN in $2 with this second pattern:

    ^(?(?:(?:0(?:0|11))?[s-]?(?|+)(44))?[s-]?(?(?:0)?[s-]?(?)?|0)([1-9]d{1,4})?[sd-]+)$

    Clean the extracted NSN of all spaces and punctuation.

    Finally, you can now check the NSN part in more detail.

    Check that the NSN begins ^(1[1-9]|2[03489]|7([457-9]|624)) if you want to restrict the input to landlines (01, 02) and mobile numbers (074, 075, 07624, 077, 078, 079).

    Consider also allowing 03 numbers as these are always charged at the same rate as 01 and 02 numbers: ^(1[1-9]|2[03489]|3[0347]|7([457-9]|624))

    You can make much more detailed checks here if you want. You can even discover the number type by the initial digits.

    This part is much simpler to program now that the dial prefix, country code, trunk prefix and any puncuation clutter has been dumped.

    There’s a very full list of patterns at: http://www.aa-asterisk.org.uk/index.php/Regular_Expressions_for_Validating_and_Formatting_GB_Telephone_Numbers

    RegEx stuff is hard, very hard. I hope these notes are useful.

    (revised post, fixes typos)

  9. You need to escape the +’s before each of the +44′s other than that seems to work great for a simple number validation.

Leave a Reply to Bob Cancel reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>