4

I have a javascript regex which validates UK postcodes. It works well, but it doesn't take into account that some people write it with spaces in the middle and others don't. I've tried to add this but cant work it out :S UK postcodes are mainly 2 letters followed by 1 or 2 numbers, optional whitespace & 1 number and 2 letters.

Here is my regex which validates postcodes without spaces:

[A-PR-UWYZa-pr-uwyz0-9][A-HK-Ya-hk-y0-9][AEHMNPRTVXYaehmnprtvxy0-9]?[ABEHMNPRVWXYabehmnprvwxy0-9]?{1,2}[0-9][ABD-HJLN-UW-Zabd-hjln-uw-z]{2}|(GIRgir){3} 0(Aa){2})$/g

Any ideas?

Edit

I changed the regex as I realised one group was missing lowercase chars.

Phil Young
  • 1,334
  • 3
  • 21
  • 43
  • Why do you want to validate postcodes in the client-side? I'd rather do strict validation on the server-side, since a malicious user could insert invalid data regardless of your client-side checks. – jsalonen Jun 18 '12 at 11:27
  • 1
    @jsalonen, this is not "malicious input" of course server-side checks are a must! But you also want to show your users on client-size "Oh excuse me sir, I think you made a mistake there, would you like to correct it" – Adi Jun 18 '12 at 11:28
  • 1
    If you are checking postal codes on the server-side you could reuse that code in client-side checks: 1) send data to server for validation, 2) if validation fails (on server-side) return back to form with a specific error message. By doing this way, you wouldn't need to maintain two separate postcode checking codes! – jsalonen Jun 18 '12 at 11:30
  • The postcode validation fires an immediate alert box before an ajax call to the server (to help ease traffic), where it is validated on the server side as well. As soon as I get this regex working, I can convert it to php. And @Adnan, that regex was adapted by me from a google search, I'm not quite that rookieish! :P – Phil Young Jun 18 '12 at 11:34
  • @jsalonen, So basically what you're saying is this, EVERY TIME a user makes a little mistake (extra space in the postal code, for example) I have to send to the server and then get a response then my call back function would act accordingly. Great job! – Adi Jun 18 '12 at 11:34
  • I've just checked the exact same RegEx in the first link in that google search with http://regexpal.com/ . Working like a charm, try it out. – Adi Jun 18 '12 at 11:38
  • @AdnanShammout Yes. I'm talking about alternative solution that has some trade-offs (both good and bad). – jsalonen Jun 18 '12 at 11:41
  • 4
    @PhilFaceplantYoung `/i` makes your regex case insensitive: `[A-PR-UWYZ0-9][A-HK-Y0-9][AEHMNPRTVXY0-9]?[ABEHMNPRVWXY0-9]?{1,2}[0-9][ABD-HJLN-UW-Z]{2}|(GIR){3} 0A{2})$/gi` – Stefan Jun 18 '12 at 11:42
  • @AdnanShammout on my site, it only matches postcodes all in capitals with a space. People use a mixture of characters and optional spaces, so it doesn't cover all options. For example, on Regexpal, `DN15 9YG` validates but `dn159yg` doesn't and both are valid postcodes. – Phil Young Jun 18 '12 at 11:45
  • 1
    BFPO postcodes are formatted very differently – symcbean Jun 18 '12 at 11:48
  • 1
    Could always just cheat and just convert it to upper case and remove any spaces before passing it to the Regex. – msanders Jun 18 '12 at 11:53
  • @symcbean So are PO box addresses, but I am going to capture them after I validate a standard UK postcode. – Phil Young Jun 18 '12 at 11:58
  • @Adnan Well, ironically searching for `UK Postcode Regex`, this is the top Google result; so errrm.. ;) – MackieeE Mar 25 '14 at 10:17
  • possible duplicate of [UK Postcode Regex (Comprehensive)](http://stackoverflow.com/questions/164979/uk-postcode-regex-comprehensive) – Gajus Dec 02 '14 at 17:39
  • 1
    Don't forget that the Cities of London and Westminster include the format EC2A 1AA, WC1A 1AA etc. – Martin Greenaway Oct 26 '17 at 16:35

5 Answers5

6

2 letters followed by 1 or 2 numbers, optional whitespace & 1 number and 2 letters.

Example:

/^[a-z]{2}\d{1,2}\s*\d[a-z]{2}$/i

Explained with http://www.myregextester.com/

  ^                        the beginning of the string
----------------------------------------------------------------------
  [a-z]{2}                 any character of: 'a' to 'z' (2 times)
----------------------------------------------------------------------
  \d{1,2}                  digits (0-9) (between 1 and 2 times
                           (matching the most amount possible))
----------------------------------------------------------------------
  \s*                      whitespace (\n, \r, \t, \f, and " ") (0 or
                           more times (matching the most amount
                           possible))
----------------------------------------------------------------------
  \d                       digits (0-9)
----------------------------------------------------------------------
  [a-z]{2}                 any character of: 'a' to 'z' (2 times)
----------------------------------------------------------------------
  $                        before an optional \n, and the end of the
                           string
Qtax
  • 33,241
  • 9
  • 83
  • 121
  • @ThisGuyHasTwoThumbs no need to use `{1}` nor include both cases if using `/i`, i.e.: `/^[a-z]{1,2}\d{1,2}\s*\d[a-z]{2}$/i`. `\d{1,2}` can also be written as `\d\d?`. – Qtax Apr 25 '17 at 08:39
6

An alternative solution would be to remove all spaces from the string, then run it through the regular expression that you already have:

var postalCode = '…';
postalCode = postalCode.replace(/\s/g, ''); // remove all whitespace
yourRegex.test(postalCode); // `true` or `false`
Mathias Bynens
  • 144,855
  • 52
  • 216
  • 248
3

According to an archived page I found, the spec is:

Pattern    w/o space   RLE                General
AN NAA     ANNAA       A1 N2 A2         | A{1,2} N{2,3} A2
ANN NAA    ANNNAA      A1 N3 A2         |
AAN NAA    AANNAA      A2 N2 A2         |
AANN NAA   AANNNAA     A2 N3 A2         |

ANA NAA    ANANAA      A1 N1 A1 N1 A2   | A{1,2} N1 A1 N1 A2  
AANA NAA   AANANAA     A2 N1 A1 N1 A2   |

GIR 0AA    We are British and for every rule there must be an 
           equal and opposite exception.

Maybe this is too much hassle to bother with in a page validation. Remember, you'll have to maintain it if there's ever a change. Consider a minimum check like ^[A-Z].+[0-9].+[A-Z]$. Don't be a 'hero' and boilerplate the code.

If you really want to validate it against that spec, the general rules (after stripping whitespace) are:

^([A-Z]{1,2})([0-9]{2,3})([A-Z]{2})$/i
^([A-Z]{1,2})([0-9])([A-Z])([0-9])([A-Z]{2})$/i
^GIR0AA$/i

As @Stefan pointed out: /i for case-insensitivity.

Once you have done this, you can match the groups (hence the braces), and check that the letters match the restricted ranges in the document. At this point you can even maintain a list of allowed one and two-letter codes for postcode areas.

The general rule for separating the Incode (chunk before the space) from the Outcode (chunk after the space) seems to be that the Outcode starts from the last number (even for GIR).

Frankly, I would stop bothering after the basic check. If it's worth validating against a more complete spec, then it's probably worth checking that the postcode area exists, and if that's worthwhile you might as well connect to a real service that extracts the address from the postcode. Those services will happily inform you that a postcode doesn't exist, which is a more robust and maintainable check than you could ever want to write.

[Edit: there's another spec on Wikipedia of course]

Phil H
  • 19,928
  • 7
  • 68
  • 105
2

We've found that most regex don't fully cover UK post codes. We found it needs to cover these options:

  • A1 1AA
  • A1A 1AA
  • AA11 1AA

Based on that, I'd recommend:

/^([A-Z][A-Z0-9]?[A-Z0-9]?[A-Z0-9]? {1,2}[0-9][A-Z0-9]{2})$/;

The GIR0AA postcode used to belong to Girobank but is no longer supported, see reference: http://en.wikipedia.org/wiki/Postcodes_in_the_United_Kingdom

MackieeE
  • 11,751
  • 4
  • 39
  • 56
devgroop
  • 129
  • 4
1

I don't know how UK postal code are done, and I didn't understand it from your description. By the way, you can add \s{0,1} where you need to say "here we could have a space". It means "0 or 1 space".

Zagorax
  • 11,440
  • 8
  • 44
  • 56