You can use the following regex to validate UK postcode:
$bs7666 = '(GIR 0AA|[A-PR-UWYZ]([0-9]{1,2}|([A-HK-Y][0-9]|[A-HK-Y][0-9]([0-9]|[ABEHMNPRV-Y]))|[0-9][A-HJKS-UW])[0-9][ABD-HJLNP-UW-Z]{2})';
which is the published British Standard for Post Code format
OR
$allexisting = '(((^[BEGLMNS][1-9]\d?) | (^W[2-9] ) | ( ^( A[BL] | B[ABDHLNRST] | C[ABFHMORTVW] | D[ADEGHLNTY] | E[HNX] | F[KY] | G[LUY] | H[ADGPRSUX] | I[GMPV] | JE | K[ATWY] | L[ADELNSU] | M[EKL] | N[EGNPRW] | O[LX] | P[AEHLOR] | R[GHM] | S[AEGKL-PRSTWY] | T[ADFNQRSW] | UB | W[ADFNRSV] | YO | ZE ) \d\d?) | (^W1[A-HJKSTUW0-9]) | (( (^WC[1-2]) | (^EC[1-4]) | (^SW1) ) [ABEHMNPRVWXY] ) ) (\s*)? ([0-9][ABD-HJLNP-UW-Z]{2})) | (^GIR\s?0AA)';
which validates all existing postcodes, which may change in the future
These will of course only work against full postcodes. What you are asking is how to match just the first part, the Incode, which identifies the sorting office and hence geographic location. For that you just need:
$incode = 'GIR 0AA|[A-PR-UWYZ]([0-9]{1,2}|([A-HK-Y][0-9]|[A-HK-Y][0-9]([0-9]|[ABEHMNPRV-Y]))|[0-9][A-HJKS-UW])';
You should realise that incodes cover very different sized areas, and using the leading character(s) will not work for a geographic search: eg (from my postcode database)
('CB3', NULL, '1AA', 'AZZ', 'CAMBRIDGE', 'Cambridgeshire'),
('CB4', NULL, '1AA', 'AZZ', 'CAMBRIDGE', 'Cambridgeshire'),
('CB5', NULL, '1AA', 'AZZ', 'CAMBRIDGE', 'Cambridgeshire'),
('CB6', NULL, '1AA', 'AZZ', 'ELY', 'Cambridgeshire'),
('CB7', NULL, '1AA', 'AZZ', 'ELY', 'Cambridgeshire'),
('CB8', NULL, '1AA', 'AZZ', 'NEWMARKET', 'Suffolk'),
('CB9', NULL, '1AA', 'AZZ', 'HAVERHILL', 'Suffolk'),
('CB10', NULL, '1AA', 'AZZ', 'SAFFRON WALDEN', 'Essex'),
('CB11', NULL, '1AA', 'AZZ', 'SAFFRON WALDEN', 'Essex'),
('CB21', NULL, '1AA', 'AZZ', 'CAMBRIDGE', 'Cambridgeshire'),
OR
('AL5', NULL, '1AA', 'AZZ', 'HARPENDEN', 'Hertfordshire'),
('AL6', NULL, '1AA', 'AZZ', 'WELWYN', 'Hertfordshire'),
('AL7', '1AA-9AE', '1AA', '9AE', 'WELWYN GARDEN CITY', 'Hertfordshire'),
('AL7', '9AG', '9AG', '9AG', 'WELWYN', 'Hertfordshire'),
('AL7', '9AH-9DA', '9AH', '9DA', 'WELWYN GARDEN CITY', 'Hertfordshire'),
('AL7', '9DB-9DD', '9DB', '9DD', 'WELWYN', 'Hertfordshire'),
('AL7', '9DL-9EL', '9DL', '9EL', 'WELWYN GARDEN CITY', 'Hertfordshire'),
('AL7', '9EN', '9EN', '9EN', 'WELWYN', 'Hertfordshire'),
('AL7', '9EP-9ER', '9EP', '9ER', 'WELWYN GARDEN CITY', 'Hertfordshire'),
('AL7', '9ES', '9ES', '9ES', 'WELWYN', 'Hertfordshire'),
('AL7', '9ET-9SA', '9ET', '9SA', 'WELWYN GARDEN CITY', 'Hertfordshire'),
('AL8', NULL, '1AA', 'AZZ', 'WELWYN GARDEN CITY', 'Hertfordshire'),
('AL9', NULL, '1AA', 'AZZ', 'HATFIELD', 'Hertfordshire'),
('AL10', NULL, '1AA', 'AZZ', 'HATFIELD', 'Hertfordshire'),
Here, just using AL7 will give you towns that are 10 miles apart.
So you must have the full incode for a geographic location search