@sroussey/parse-address
Version:
International street address parser for 220 jurisdictions (US, CA + 218 countries and territories), with SEC EDGAR country-code resolution
135 lines • 5.16 kB
JavaScript
import XRegExp from "xregexp";
import { each, isNumeric, capitalize } from "../../utils.js";
import { normalizeMap } from "./normalize.js";
import { streetAbbrevsToShortCodeMap } from "./street-abbrevs.js";
import addressRuleset from "./ruleset.js";
export class AddressParserUS {
normalizeAddress(parts) {
const self = this;
if (!parts)
return null;
const parsed = {};
Object.keys(parts).forEach((part) => {
if (["input", "index"].includes(part) || isNumeric(part)) {
return;
}
const key = isNumeric(part.split("_").pop())
? part.split("_").slice(0, -1).join("_")
: part;
if (parts[part]) {
parsed[key] = parts[part].trim().replace(/^\s+|\s+$|[^\w\s\-#&]/g, "");
}
});
each(normalizeMap, function (map, key) {
if (parsed[key] && map[parsed[key].toLowerCase()]) {
parsed[key] = map[parsed[key].toLowerCase()];
}
});
["type", "type1", "type2"].forEach(function (key) {
if (key in parsed) {
// Map the address short code
const lowerCaseType = parsed[key].toLowerCase();
parsed[`short_street_${key}`] =
self.findStreetTypeShortCode(lowerCaseType);
parsed[key] =
parsed[key].charAt(0).toUpperCase() +
parsed[key].slice(1).toLowerCase();
}
});
if (parsed.city) {
const directionCode = addressRuleset.directionCode;
parsed.city = XRegExp.replace(parsed.city, XRegExp(`^(?<dircode>${addressRuleset.dircode})\\s+(?=\\S)`, "ix"), function (match) {
return capitalize(directionCode[match.dircode.toUpperCase()]) + " ";
});
}
switch (parts.number) {
case "One":
parsed.number = "1";
break;
case "Two":
parsed.number = "2";
break;
case "Three":
parsed.number = "3";
break;
case "Four":
parsed.number = "4";
break;
case "Five":
parsed.number = "5";
break;
case "Six":
parsed.number = "6";
break;
case "Seven":
parsed.number = "7";
break;
case "Eight":
parsed.number = "8";
break;
case "Nine":
parsed.number = "9";
break;
}
parsed.country = "US";
return parsed;
}
parseStreet(street_address) {
const parts = XRegExp.exec(street_address, addressRuleset.street_address);
return this.normalizeAddress(parts);
}
parseAddress(address) {
const parts = XRegExp.exec(address, addressRuleset.address);
return this.normalizeAddress(parts);
}
parseInformalAddress(address) {
const parts = XRegExp.exec(address, addressRuleset.informal_address);
return this.normalizeAddress(parts);
}
parsePoAddress(address) {
const parts = XRegExp.exec(address, addressRuleset.po_address);
return this.normalizeAddress(parts);
}
parseLocation(address) {
if (XRegExp(addressRuleset.corner, "xi").test(address)) {
return this.parseIntersection(address);
}
if (XRegExp("^" + addressRuleset.po_box, "xi").test(address)) {
return this.parsePoAddress(address);
}
return this.parseAddress(address) || this.parseInformalAddress(address);
}
parseIntersection(address) {
let parts = XRegExp.exec(address, addressRuleset.intersection);
// @ts-ignore
parts = this.normalizeAddress(parts);
if (parts) {
parts.type2 = parts.type2 || "";
parts.type1 = parts.type1 || "";
if ((parts.type2 && !parts.type1) || parts.type1 === parts.type2) {
let type = parts.type2;
const short_street_type = parts.short_street_type2;
type = XRegExp.replace(type, /s\W*$/, "");
if (XRegExp(`^${addressRuleset.type}$`, "ix").test(type)) {
parts.type1 = parts.type2 = type;
parts.short_street_type1 = parts.short_street_type2 =
short_street_type;
}
}
}
return parts;
}
findStreetTypeShortCode(streetType) {
const blankShortCode = "BL";
if (!streetType) {
return blankShortCode;
}
const matchedEntry = Object.entries(streetAbbrevsToShortCodeMap).find(([_, streetTypeString]) => {
// Check against singular and plural versions
return (streetTypeString === streetType ||
`${streetTypeString}s` === streetType);
});
return matchedEntry ? matchedEntry[0] : blankShortCode;
}
}
//# sourceMappingURL=parser.js.map