Skip to content

Instantly share code, notes, and snippets.

@daliborgogic
Last active October 14, 2022 16:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save daliborgogic/7cce7023e7d1f3d9ff0f8a630e765aab to your computer and use it in GitHub Desktop.
Save daliborgogic/7cce7023e7d1f3d9ff0f8a630e765aab to your computer and use it in GitHub Desktop.
Checks for a valid postcode
{
"scripts": {
"test": "vitest"
},
"devDependencies": {
"vitest": "^0.24.3"
}
}
import { expect, test } from 'vitest'
import { isGBPostcode, isPostcode } from '../src/uses/usePostcode.js'
test('is GB', () => {
expect(isGBPostcode('SW1W 0NY')).toBe(true)
expect(isGBPostcode('PO16 7GZ')).toBe(true)
expect(isGBPostcode('GU16 7HF')).toBe(true)
expect(isGBPostcode('L1 8JQ')).toBe(true)
expect(isGBPostcode('L1 8JQ$')).toBe(false)
})
test('is DE', () => {
expect(isPostcode('DE', '84419')).toBe(true)
})
test('is AT', () => {
expect(isPostcode('AT', '1010')).toBe(true)
expect(isPostcode('AT', '1423')).toBe(true)
expect(isPostcode('AT', '5020')).toBe(true)
})
test('is Ireland', () => {
expect(isPostcode('IE', 'A65 F4E2')).toBe(true)
expect(isPostcode('IE', 'D02 AF30')).toBe(true)
})
const normalizePostcode = postcode => postcode.toUpperCase().trim().replace(/\s/g, '')
export const isGBPostcode = postcode => {
// Permitted letters depend upon their position in the postcode.
// https://en.wikipedia.org/wiki/Postcodes_in_the_United_Kingdom#Validation.
const ALPHA1 = '[abcdefghijklmnoprstuwyz]' // Character 1.
const ALPHA2 = '[abcdefghklmnopqrstuvwxy]' // Character 2.
const ALPHA3 = '[abcdefghjkpstuw]' // Character 3 == ABCDEFGHJKPSTUW.
const ALPHA4 = '[abehmnprvwxy]' // Character 4 == ABEHMNPRVWXY.
const ALPHA5 = '[abdefghjlnpqrstuwxyz]' // Character 5 != CIKMOV.
const pcexp = []
// Expression for postcodes: AN NAA, ANN NAA, AAN NAA, and AANN NAA.
pcexp[0] = `^(${ALPHA1}{1}${ALPHA2}{0,1}[0-9]{1,2})([0-9]{1}${ALPHA5}{2})$`
// Expression for postcodes: ANA NAA.
pcexp[1] = `^(${ALPHA1}{1}[0-9]{1}${ALPHA3}{1})([0-9]{1}${ALPHA5}{2})$`
// Expression for postcodes: AANA NAA.
pcexp[2] = `^(${ALPHA1}{1}${ALPHA2}[0-9]{1}${ALPHA4})([0-9]{1}${ALPHA5}{2})$`
// Exception for the special postcode GIR 0AA.
pcexp[3] = '^(gir)(0aa)$'
// Standard BFPO numbers.
pcexp[4] = '/^(bfpo)([0-9]{1,4})$/'
// c/o BFPO numbers.
pcexp[5] = '/^(bfpo)(c/o[0-9]{1,3})$/'
// Load up the string to check, converting into lowercase and removing spaces.
postcode = postcode.toLowerCase().replace(/\s/g, '')
// Assume we are not going to find a valid postcode.
let valid = false
// Check the string against the six types of postcodes.
for (const el of pcexp) {
if (postcode.match(el)) {
valid = true
break
}
}
return valid
}
export const isPostcode = (country, postcode) => {
// Assume we are not going to find a valid postcode.
let valid = true
if (postcode.replace(/^[\s\-A-Za-z0-9]+$/, '').trim().length > 0) {
return false;
}
switch (country) {
case 'AT':
valid = /^([0-9]{4})$/.test(postcode)
break
case 'BA':
valid = /^([7-8]{1})([0-9]{4})$/.test(postcode)
break
case 'BE':
valid = /^([0-9]{4})$/i.test(postcode)
break
case 'BR':
valid = /^([0-9]{5})([-])?([0-9]{3})$/.test(postcode)
break
case 'CH':
valid = /^([0-9]{4})$/i.test(postcode)
break
case 'DE':
valid = /^([0]{1}[1-9]{1}|[1-9]{1}[0-9]{1})[0-9]{3}$/.test(postcode)
break
case 'ES':
case 'FR':
case 'IT':
valid = /^([0-9]{5})$/i.test(postcode)
break
case 'GB':
valid = isGBPostcode(postcode)
break
case 'HU':
valid = /^([0-9]{4})$/i.test(postcode)
break
case 'IE':
valid = /([AC-FHKNPRTV-Y]\d{2}|D6W)[0-9AC-FHKNPRTV-Y]{4}/.test(normalizePostcode(postcode))
break
case 'IN':
valid = /^[1-9]{1}[0-9]{2}\s{0,1}[0-9]{3}$/.test(postcode)
break
case 'JP':
valid = /^([0-9]{3})([-]?)([0-9]{4})$/.test(postcode)
break
case 'PT':
valid = /^([0-9]{4})([-])([0-9]{3})$/.test(postcode)
break
case 'PR':
case 'US':
valid = /^([0-9]{5})(-[0-9]{4})?$/i.test(postcode)
break
case 'CA':
// CA Postal codes cannot contain D,F,I,O,Q,U and cannot start with W or Z. https://en.wikipedia.org/wiki/Postal_codes_in_Canada#Number_of_possible_postal_codes.
valid = /^([ABCEGHJKLMNPRSTVXY]d[ABCEGHJKLMNPRSTVWXYZ])([ ])?(d[ABCEGHJKLMNPRSTVWXYZ]d)$/i.test(postcode)
break
case 'PL':
valid = /^([0-9]{2})([-])([0-9]{3})$/.test(postcode)
break
case 'CZ':
case 'SK':
valid = /^([0-9]{3})(s?)([0-9]{2})$/.test(postcode)
break
case 'NL':
valid = /^([1-9][0-9]{3})(s?)(?!SA|SD|SS)[A-Z]{2}$/i.test(postcode)
break
case 'SI':
valid = /^([1-9][0-9]{3})$/.test(postcode)
break
case 'LI':
valid = /^(94[8-9][0-9])$/.test(postcode)
break
default:
valid = true
break
}
return valid
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment