Options
All
  • Public
  • Public/Protected
  • All
Menu

UK Clear Addressing

Correctly parse and format UK Addresses in Royal Mail's Postcode Address File

CI Release Dependency Status Coverage Status Try uk-clear-addressing on RunKit

Parses Postcode Address File records into correctly formatted address recognised by Royal Mail according to its Clear Addressing Guidelines.

Produces consistent address lines, a post town line and a postcode line.

Features

Correct Addressing

  • Correctly format UK addresses using Royal Mail's Postcode Address File
  • Produces 3 address lines and premise attributes based on building_name, sub_building_name and building_number
  • Address sorting function
  • Extensive test suite

Links

Getting Started

Installation

npm install uk-clear-addressing

Formatting Addresses

Extract formatted address lines

Use the Address class to parse a PAF Record

Formatted address lines can be extracted using instance accessors like line_1, line_2, line_3 and premise.

const { Address } = require('uk-clear-addressing');

const pafRecord = {
  postcode: "WS11 5SB",
  post_town: "CANNOCK",
  thoroughfare: "Pye Green Road",
  building_name: "Flower House 189A",
  organisation_name: 'S D Alcott Florists',
};

const {
  line_1,
  line_2,
  line_3,
  premise,
  post_town,
  postcode
} = new Address(pafRecord);

Extract a formatted address object

Alternatively extract a formatted address object using .formattedAddress.

const { Address } = require('uk-clear-addressing');

const address = new Address({
  postcode: "WS11 5SB",
  post_town: "CANNOCK",
  thoroughfare: "Pye Green Road",
  building_name: "Flower House 189A",
  organisation_name: 'S D Alcott Florists',
});

console.log(address.formattedAddress());
//  {
//    postcode: 'WS11 5SB',
//    post_town: 'CANNOCK',
//    line_1: 'S D Alcott Florists',
//    line_2: 'Flower House',
//    line_3: '189a Pye Green Road',
//    premise: "Flower House, 189a"
//  }

Sorting Addresses

Address.sort implements a comparison function, which allows you to compare Address instances. This can readily be passed into Array.prototype.sort

const addresses = await query("SELECT * FROM postcode_address_file LIMIT 10");

addresses
  .map(address => new Address(address)) // Instantiate an `Address` instances
  .sort(Address.sort)                   // Now sort
  // Print an example to console
  .forEach(address => console.log(address.line_1));
  // "190 Elm Road"
  // "190a Elm Road"
  // "191 Elm Road"
  // "191a Elm Road"
  // "192 Elm Road"
  // "193 Elm Road"
  // "193a Elm Road"
  // "197 Elm Road"
  // "197a Elm Road"
  // "199 Elm Road"

Testing

Many of the regular and edge cases are documented in the test. To run the test suite:

npm test

If you find an edge case, please feel free to make a pull request. However be sure to include a test which documents the specific case being handled.

Parameters

Below is a list of address fragments. For the address to be properly formatted, you need to pass in all the address fragments available to you.

Premises Elements

  • Sub Building Name (e.g. ‘Flat 1’)
  • Building Name (e.g. ‘Rose Cottage’)
  • Building Number (e.g. ‘22’)
  • Organisation Name (e.g. ‘Cath’s Cakes’)
  • PO Box number

Thoroughfare Elements

  • Dependant Thoroughfare Name (e.g. ‘Cheshunt’)
  • Dependant Thoroughfare Descriptor (e.g. ‘Mews’ or ‘Court’)
  • Thoroughfare Name (e.g. ‘Cypress’)
  • Thoroughfare Descriptor (e.g. ‘Road’ or ‘Street’)

Locality Elements

  • Double Dependant Locality (e.g. ‘Tyre Industrial Estate’)
  • Dependant Locality (e.g. ‘Blantyre’)
  • Post Town (e.g. ‘GLASGOW’)

Licence

MIT

Index

Type aliases

EmptyString

EmptyString: ""

LocalityElements

LocalityElements: "dependant_locality" | "double_dependant_locality" | "thoroughfare" | "dependant_thoroughfare"

SortingElems

SortingElems: "building_number" | "building_name" | "sub_building_name" | "organisation_name" | "department_name" | "po_box"

Variables

Const BUILDING_RANGE_REGEX

BUILDING_RANGE_REGEX: RegExp = /^(\d.*\D.*\d|\d(.*\d)?[a-z]|[a-z])$/i

Const STARTS_CHAR_REGEX

STARTS_CHAR_REGEX: RegExp = /^[a-z]$/i

Const localityElements

localityElements: LocalityElements[] = ["dependant_locality","double_dependant_locality","thoroughfare","dependant_thoroughfare",]

Const nameExceptionRegex

nameExceptionRegex: RegExp = /^(\d|\d.*\d|\d(.*\d)?[a-z]|[a-z])$/i

Const singleCharacterRegex

singleCharacterRegex: RegExp = /^[A-Z]$/i

Const sortingElems

sortingElems: ReadonlyArray<SortingElems> = ["building_number","building_name","sub_building_name","organisation_name","department_name","po_box",]

Const unitPrefixRegex

unitPrefixRegex: RegExp = /^(back\sof|blocks?|building|maisonettes?|rear\sof|shops?|stalls?|suites?|units?)/i

Functions

Const appendOrganisationInfo

  • appendOrganisationInfo(elems: AddressElements, address: Address): void
  • Parameters

    • elems: AddressElements
    • address: Address

    Returns void

Const checkBuildingRange

  • checkBuildingRange(building_name: string): BuildingRangeMatch | void
  • Detects whether a building name contains a range

    Parameters

    • building_name: string

    Returns BuildingRangeMatch | void

Const combinePremise

  • Merges premise elements ordered by precedence into a formatted address

    Parameters

    • elems: AddressElements
    • address: Address
    • premise: string

    Returns FormattedPremise

Const extract

Const extractFloat

  • extractFloat(address: AddressRecord, elem: "northings" | "eastings" | "longitude" | "latitude" | "county" | "traditional_county" | "administrative_county" | "postal_county" | "district" | "ward" | "country" | "udprn" | "umprn" | "postcode" | "building_number" | "building_name" | "sub_building_name" | "department_name" | "organisation_name" | "po_box" | "post_town" | "dependant_locality" | "double_dependant_locality" | "thoroughfare" | "dependant_thoroughfare" | "postcode_type" | "su_organisation_indicator" | "delivery_point_suffix"): number | ""
  • Parameters

    • address: AddressRecord
    • elem: "northings" | "eastings" | "longitude" | "latitude" | "county" | "traditional_county" | "administrative_county" | "postal_county" | "district" | "ward" | "country" | "udprn" | "umprn" | "postcode" | "building_number" | "building_name" | "sub_building_name" | "department_name" | "organisation_name" | "po_box" | "post_town" | "dependant_locality" | "double_dependant_locality" | "thoroughfare" | "dependant_thoroughfare" | "postcode_type" | "su_organisation_indicator" | "delivery_point_suffix"

    Returns number | ""

Const extractInteger

  • extractInteger(address: AddressRecord, elem: "northings" | "eastings" | "longitude" | "latitude" | "county" | "traditional_county" | "administrative_county" | "postal_county" | "district" | "ward" | "country" | "udprn" | "umprn" | "postcode" | "building_number" | "building_name" | "sub_building_name" | "department_name" | "organisation_name" | "po_box" | "post_town" | "dependant_locality" | "double_dependant_locality" | "thoroughfare" | "dependant_thoroughfare" | "postcode_type" | "su_organisation_indicator" | "delivery_point_suffix"): number | ""
  • Parameters

    • address: AddressRecord
    • elem: "northings" | "eastings" | "longitude" | "latitude" | "county" | "traditional_county" | "administrative_county" | "postal_county" | "district" | "ward" | "country" | "udprn" | "umprn" | "postcode" | "building_number" | "building_name" | "sub_building_name" | "department_name" | "organisation_name" | "po_box" | "post_town" | "dependant_locality" | "double_dependant_locality" | "thoroughfare" | "dependant_thoroughfare" | "postcode_type" | "su_organisation_indicator" | "delivery_point_suffix"

    Returns number | ""

Const extractIntegerAttribute

  • extractIntegerAttribute(a: Address): string
  • Takes an Address instance and returns a building number, first checking for name exceptions in building_name and sub_building_name fields

    Parameters

    Returns string

Const formatElem

  • formatElem(e: string): string
  • Formats an address element

    • If a single letter element, suffix a comma
    • Otherwise return address element

    Parameters

    • e: string

    Returns string

Const formatter

Const hasUnitPrefix

  • hasUnitPrefix(e: string): boolean
  • Test for whether a string begins with a unit prefix

    E.g. Back of 10A => true

    Parameters

    • e: string

    Returns boolean

Const isEmpty

  • isEmpty(s: string): boolean
  • Parameters

    • s: string

    Returns boolean

Const isSingleCharacter

  • isSingleCharacter(c: string): boolean
  • Returns true if string matches rule (iii) of exception rule (above)

    Parameters

    • c: string

    Returns boolean

Const lastElem

  • lastElem(a: AddressElements): string
  • Non-desctructively return last elem

    Parameters

    • a: AddressElements

    Returns string

Const nameException

  • nameException(n: string): boolean
  • Exception Rule indicators: i) First and last characters of the Building Name are numeric (eg ‘1to1’ or ’100:1’) ii) First and penultimate characters are numeric, last character is alphabetic (eg 12A’) iii) Building Name has only one character (eg ‘A’)

    Parameters

    • n: string

    Returns boolean

Const notEmpty

  • notEmpty(a: string): boolean
  • Parameters

    • a: string

    Returns boolean

Const po_box

Const premiseLocalities

  • premiseLocalities(address: Address): AddressElements
  • Returns an array of localities according to precedent recorded in localityElements

    Parameters

    Returns AddressElements

Const prependLocality

  • prependLocality(localities: AddressElements, premise: string): void
  • Parameters

    • localities: AddressElements
    • premise: string

    Returns void

Const rule1

  • Rule 1 - No building name, number or sub building name No premise elements detected (typically organisation name)

    Parameters

    Returns FormattedPremise

Const rule2

Const rule3

  • Rule 3 - Building name only

    Check format of Building Name (see note (a) above). If the Exception Rule applies, the Building Name should appear at the beginning of the first Thoroughfare line, or the first Locality line if there is no Thoroughfare information.

    When a building has a name AND a number range, both must be held in the Building Name field because the Building Number field can only hold numeric characters.

    If an address has a building name with text followed by a space and then completed by numerics/numeric ranges with the numeric part an exception (see Note (a) above), the numerics/numeric range are treated as a building number, and the text part is treated as the Building Name and the numerics/numeric range are split off to appear at the beginning of the first Thoroughfare line, or the first Locality line if there is no Thoroughfare.

    Parameters

    Returns FormattedPremise

Const rule4

  • Rule 4 - Building Name and Number

    The Building Name should appear on the line preceding the Thoroughfare and/or Locality information. The Building Number should appear at the beginning of the first Thoroughfare line. If there is no Thoroughfare information then the Building Number should appear at the beginning of the first Locality line.

    Parameters

    Returns FormattedPremise

Const rule5

  • Rule 5 - Sub Building Name and Building Number

    The Sub Building Name should appear on the line preceding the Thoroughfare and Locality information. The Building Number should appear at the beginning of the first Thoroughfare line. If there is no Thoroughfare information then the Building Number should appear at the beginning of the first Locality line.

    Parameters

    Returns FormattedPremise

Const rule6

  • Rule 6 - Sub building name and building name

    Check the format of Sub Building Name (see Note (a) above). If the Exception Rule applies, the Sub Building Name should appear on the same line as, and before, the Building Name.

    Otherwise, the Sub Building Name should appear on a line preceding the Building Name, Thoroughfare and Locality information

    Check format of Building Name (see note (a) above) If the Exception Rule applies, the Building Name should appear at the beginning of the first Thoroughfare line, or the first Locality line if there is no Thoroughfare information. Otherwise, the Building Name should appear on a line preceding the Thoroughfare and Locality information.

    Parameters

    Returns FormattedPremise

Const rule7

  • Rule 7 - Sub building name, building name and building number

    If the Exception Rule applies, the Sub Building Name should appear on the same line as and before the Building Name.

    Parameters

    Returns FormattedPremise

Const sort

  • Sorts Address objects based on the precedence outlined in sortingElems

    Parameters

    Returns number

Const undocumentedRule

  • Undocumented Rule

    This rule should not exist as it is not listed in the developer docs. But some records in the wild only have a sub building name

    Parameters

    Returns FormattedPremise