# validation.uk-postcode Returns a result object rather than a boolean because the caller almost always wants both answers at once: whether to accept the value, and what to store. Storing what the user typed means "sw1a1aa" and "SW1A 1AA" are two different rows for one address; storing `normalised` means they are one. Splitting outward from inward is the difference between "can we deliver here" and "which delivery office is this", and callers that only want the yes or no have isUkPostcode / is_uk_postcode. Malformed input returns valid=false with nulls rather than throwing, so `result.normalised ?? typed` is always safe and a bad address never becomes an exception in the middle of a form submission. FORMAT: the outward code is one of six shapes - A9, A99, A9A, AA9, AA99, AA9A - and the inward code is always 9AA. The letter restrictions are real rules, not decoration, and they are what rejects plausible-looking strings: Q, V and X never start an area; I, J and Z are never the second letter of a two-letter area; the third position of the A9A form is restricted to ABCDEFGHJKPSTUW; the fourth position of the AA9A form to ABEHMNPRVWXY; and the final two letters exclude C, I, K, M, O and V, which are the ones most easily misread by a person or a sorting machine. GIR 0AA is accepted as a special case. It was issued to Girobank in 1968, fits none of the six shapes, and is still valid on an address label; a validator that rejects it is wrong in a way that is very hard for the affected user to argue with. NORMALISATION: every ASCII space is stripped and exactly one is reinserted before the final three characters. People put the space in the wrong place far more often than they leave it out, so its original position carries no information worth preserving. Only the ASCII space is stripped - a hyphen or a non-breaking space makes the value invalid rather than being cleaned up, because those mean the value came from somewhere unexpected. A WELL-FORMED POSTCODE IS NOT A REAL ADDRESS. This checks the shape, not existence: "AA1 1AA" passes every rule above and has never been issued. Only the Royal Mail Postcode Address File (PAF), or an address lookup service built on it, can tell you a postcode exists and what is at it. Use this to catch typing errors before the lookup, not instead of it. OUT OF SCOPE: BFPO numbers for British Forces addresses, the overseas territory codes (Gibraltar's GX11 1AA, the Falklands' FIQQ 1ZZ, Ascension's ASCN 1ZZ and the rest) and Crown dependency codes are not special-cased; the ones that happen to fit the six shapes pass, and the ones that do not are rejected. If you accept forces or territory mail, test for those prefixes before calling this. 2.0.0 renames the function from `ukPostcode` to `validateUkPostcode` (`validate_uk_postcode` in Python and Rust), so every validator that returns a result record is `validateX` and every one that returns a bool is `isX`. Nothing else changed; 1.0.0 stays published under the old name.