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]