Skip to content

Instantly share code, notes, and snippets.

@nalbion
Created September 26, 2019 04:55
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 nalbion/5097eb072c97204c87b3878b129f6fb8 to your computer and use it in GitHub Desktop.
Save nalbion/5097eb072c97204c87b3878b129f6fb8 to your computer and use it in GitHub Desktop.
Parse a formattedAddress
import 'mocha';
import {expect} from 'chai';
import parseFormattedAddress from './parse-formatted-address';
describe('parseFormattedAddress', () => {
it('supports addresses without country', () => {
const place = parseFormattedAddress('100 Best Road, Seven Hills NSW');
expect(place.address).to.equal('100 Best Road');
expect(place.city).to.equal('Seven Hills');
expect(place.state).to.equal('NSW');
});
it('supports Australian suburbs', () => {
const place = parseFormattedAddress('Rouse Hill NSW 2155, Australia');
expect(place.city).to.equal('Rouse Hill');
expect(place.state).to.equal('NSW');
expect(place.postalCode).to.equal('2155');
expect(place.country).to.equal('Australia');
expect(place.countryCode).to.equal('au');
});
it('supports UK postcodes', () => {
const place = parseFormattedAddress('12 Taverner Cl, Basingstoke RG21 4JD, UK');
expect(place.address).to.equal('12 Taverner Cl');
expect(place.city).to.equal('Basingstoke');
expect(place.postalCode).to.equal('RG21 4JD');
expect(place.country).to.equal('United Kingdom');
expect(place.countryCode).to.equal('uk');
});
it('supports USA addresses', () => {
const place = parseFormattedAddress('6 West 49th Street, New York, NY, USA');
expect(place.address).to.equal('6 West 49th Street');
expect(place.city).to.equal('New York');
expect(place.country).to.equal('United States');
expect(place.countryCode).to.equal('us');
});
it('supports Indian addresses', () => {
const place = parseFormattedAddress('SCF - 96, Main Market Road, Sector 6, Karnal, Haryana 132001, India');
expect(place.address).to.equal('SCF - 96, Main Market Road, Sector 6');
expect(place.city).to.equal('Karnal');
expect(place.postalCode).to.equal('132001');
expect(place.country).to.equal('India');
expect(place.countryCode).to.equal('in');
});
});
interface Address {
address?: string;
city: string;
state?: string;
postalCode?: string;
country?: string;
countryCode?: string;
}
/**
* Adapted from https://imbibe.in/blog/2017/03/10/parsing-address-components-google-maps-geocoding-api-responses/
* @param address
*/
export default function parseFormattedAddress(formattedAddress: string): Address {
const address: Address = {
city: ''
};
if(!formattedAddress) {
return address;
}
let parts = formattedAddress.split(',').map(part => part.trim());
let i = parts.length - 1;
// Generally the country is the last part of the address (or absent)
if (i >= 0) {
const part = fnParsePostalCode(parts[i], address);
if (part) {
address.country = part;
if (address.country === 'USA') {
address.countryCode = 'us';
address.country = getCountryName(address.countryCode);
} else if (address.country.length === 2) {
address.countryCode = address.country.toLowerCase();
address.country = getCountryName(address.countryCode);
} else {
address.countryCode = getCountryCode(address.country);
if (!address.countryCode) {
// it's probably not a country
address.country = undefined;
i++;
}
}
}
i--;
}
// Attempt to parse the state & postal code
if (i >= 0) {
let part = fnParsePostalCode(parts[i], address);
if (part) {
// some times the city and state are not separated by a comma
const cityAndState = part.match(/(.+) ([A-Z]+)/);
if (cityAndState) {
part = cityAndState[2];
parts[i] = cityAndState[1];
i++;
}
address.state = part;
}
i--;
}
if (i >= 0) {
const part = fnParsePostalCode(parts[i], address);
if (part) {
address.city = part;
}
i--;
}
if (i >= 0) {
parts = parts.slice(0, i + 1);
address.address = parts.join(', ');
} else if (address.countryCode === 'uk' && address.state) {
console.info('UK address with state but no street address? I don\'t think so:', JSON.stringify(address));
address.address = address.city;
address.city = address.state;
address.state = undefined;
}
console.info(`parsed '${formattedAddress}' -> ${JSON.stringify(address)}`);
return address;
}
function fnParsePostalCode(value: string, address: Address) {
const match = value.match(getPostalCodeRegEx(address.countryCode));
if (match) {
address.postalCode = match[2];
return match[1].trim();
} else {
return value;
}
}
function getPostalCodeRegEx(countryCode: string) {
return {
ca: /(.*)\b(?![DFIOQU])([A-VXY][0-9][A-Z] ?[0-9][A-Z][0-9])$/,
uk: /(.*)\b([A-Z]{1,2}[0-9R][0-9A-Z]? [0-9][ABD-HJLNP-UW-Z]{2})$/,
us: /(.*)\b([0-9]{5}(?:-[0-9]{4}))?$/
}[countryCode] || /(.*)\b(\d+)$/;
}
export function getCountryCode(country: string | {name: string; 'alpha-2': string; 'alpha-3': string;}) {
if (typeof country === 'string') {
country = country.toLowerCase();
if (country.length === 2) {
return country;
}
return {
'antarctica': 'aq',
'argentina': 'ar',
'australia': 'au',
'austria': 'at',
'bahrain': 'bh',
'belgium': 'be',
'brazil': 'br',
'canada': 'ca',
'chile': 'cl',
'china': 'cn',
'colombia': 'co',
'costa rica': 'cr',
'czech republic': 'cz',
'denmark': 'dk',
'ecuador': 'ec',
'egypt': 'eg',
'finland': 'fi',
'france': 'fr',
'germany': 'de',
'greece': 'gr',
'hong kong': 'hk',
'hungary': 'hu',
'india': 'in',
'indonesia': 'id',
'ireland': 'ie',
'israel': 'il',
'italy': 'it',
'japan': 'jp',
'kuwait': 'kw',
'luxembourg': 'lu',
'malaysia': 'my',
'mexico': 'mx',
'morocco': 'ma',
'netherlands': 'nl',
'new zealand': 'nz',
'nigeria': 'ng',
'norway': 'no',
'oman': 'om',
'pakistan': 'pk',
'panama': 'pa',
'peru': 'pe',
'philippines': 'ph',
'poland': 'pl',
'portugal': 'pt',
'qatar': 'qa',
'romania': 'ro',
'russia': 'ru',
'saudi arabia': 'sa',
'singapore': 'sg',
'south africa': 'za',
'south korea': 'kr',
'spain': 'es',
'sweden': 'se',
'switzerland': 'ch',
'taiwan': 'tw',
'thailand': 'th',
'turkey': 'tr',
'ukraine': 'ua',
'united arab emirates': 'ae',
'united kingdom': 'gb',
'united states': 'us',
'uruguay': 'uy',
'venezuela': 've',
'vietnam': 'vn',
// Aliases
'england': 'gb',
'america': 'us'
}[country];
} else {
return country['alpha-2'].toLowerCase();
}
}
export function getCountryName(countryCode: string) {
return {
'aq': 'Antarctica',
'ar': 'Argentina',
'au': 'Australia',
'at': 'Austria',
'bh': 'Bahrain',
'be': 'Belgium',
'br': 'Brazil',
'ca': 'Canada',
'cl': 'Chile',
'cn': 'China',
'co': 'Colombia',
'cr': 'Costa Rica',
'cz': 'Czech Republic',
'dk': 'Denmark',
'ec': 'Ecuador',
'eg': 'Egypt',
'fi': 'Finland',
'fr': 'France',
'de': 'Germany',
'gr': 'Greece',
'hk': 'Hong Kong',
'hu': 'Hungary',
'in': 'India',
'id': 'Indonesia',
'ie': 'Ireland',
'il': 'Israel',
'it': 'Italy',
'jp': 'Japan',
'kw': 'Kuwait',
'lu': 'Luxembourg',
'my': 'Malaysia',
'mx': 'Mexico',
'ma': 'Morocco',
'nl': 'Netherlands',
'nz': 'New Zealand',
'ng': 'Nigeria',
'no': 'Norway',
'om': 'Oman',
'pk': 'Pakistan',
'pa': 'Panama',
'pe': 'Peru',
'ph': 'Philippines',
'pl': 'Poland',
'pt': 'Portugal',
'qa': 'Qatar',
'ro': 'Romania',
'ru': 'Russia',
'sa': 'Saudi Arabia',
'sg': 'Singapore',
'za': 'South Africa',
'kr': 'South Korea',
'es': 'Spain',
'se': 'Sweden',
'ch': 'Switzerland',
'tw': 'Taiwan',
'th': 'Thailand',
'tr': 'Turkey',
'ua': 'Ukraine',
'ae': 'United Arab Emirates',
'gb': 'United Kingdom',
'us': 'United States',
'uy': 'Uruguay',
've': 'Venezuela',
'vn': 'Vietnam',
// Aliases
'uk': 'United Kingdom',
}[countryCode];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment