Name & Address Parsing
pop-parser splits a string a person typed into fields. NameParser turns Dr. John Michael Smith Jr.
into a salutation, first, middle and last name and a suffix; AddressParser turns 123 Main St Apt 4B, Springfield, IL 62704 into street number, name, route type, unit, city, state and postal code. Both are
native — no third-party parsing library.
composer require popphp/pop-parser
Parsing a Name#
Construct, parse, read the parts off:
use Pop\Parser\Name\NameParser;
$parser = new NameParser();
$parser->parse('Dr. John Michael Smith Jr.');
$parser->getSalutation(); // 'Dr.'
$parser->getFirstname(); // 'John'
$parser->getMiddlename(); // 'Michael'
$parser->getLastname(); // 'Smith'
$parser->getSuffix(); // 'Jr'
The string can go to the constructor instead, in which case parse() takes no argument. Both forms
are equivalent, and the constructor form is the one to reach for when the name arrives with the object:
use Pop\Parser\Name\NameParser;
$parser = new NameParser('John Smith');
$parser->parse();
A comma anywhere in the input switches the parser to Last, First Middle[, Suffix] — the shape a
database export or a sorted list hands you — with no flag to set:
use Pop\Parser\Name\NameParser;
$parser = new NameParser();
$parser->parse('Smith, John Michael, Jr');
$parser->getFirstname(); // 'John'
$parser->getLastname(); // 'Smith'
$parser->getSuffix(); // 'Jr'
Salutations are normalized rather than echoed back. mister, master and a bare lowercase mr all
come out as Mr., and MRS comes out as Mrs., so the value is safe to compare against or store
without a second pass of your own.
Three things that look like name parts come out separately: a recognized lastname prefix (van, von,
de), a single letter as an initial, and a parenthetical or quoted nickname.
use Pop\Parser\Name\NameParser;
$parser = new NameParser();
$parser->parse('Ludwig van Beethoven');
$parser->getLastnamePrefix(); // 'van'
$parser->getLastname(); // 'Beethoven'
$parser->getFullName(); // 'Ludwig van Beethoven'
$parser->parse('J.R. "Bob" Smith');
$parser->getFirstname(); // 'J'
$parser->getInitials(); // 'R'
$parser->getNickname(); // 'Bob'
$parser->getNickname(true); // '(Bob)'
getFullName() reassembles the given name, the prefix and the last name; getGivenName() stops after
the first name, initials and middle name. Casting to a string gives the whole thing back including the
salutation and suffix, and toArray() gives every field at once with null where nothing was found:
use Pop\Parser\Name\NameParser;
$parser = new NameParser('John Michael Smith Jr');
$parser->parse();
$parser->getGivenName(); // 'John Michael'
$parser->getFullName(); // 'John Michael Smith'
(string)$parser; // 'John Michael Smith Jr'
$parser->toArray();
// ['salutation' => null, 'firstname' => 'John', 'initials' => null, 'middlename' => 'Michael',
// 'nickname' => null, 'lastnamePrefix' => null, 'lastname' => 'Smith', 'suffix' => 'Jr']
Every getter has a matching has*() — hasSuffix(), hasNickname(), hasMiddlename() — which
returns true only when that part was actually found. Use those rather than testing the getter against
null, because they say what you mean.
A single-word input becomes a first name, so check hasLastname() and fall back to getFirstname() when
you are normalizing a surname column.
The only input that raises is one with nothing in it. parse() with no data set anywhere, or with a
string that normalizes to empty, throws Pop\Parser\Exception with "Error: You must pass a name string
to the parser object."
Parsing an Address#
The same shape, with more fields:
use Pop\Parser\Address\AddressParser;
$parser = new AddressParser();
$parser->parse('123 Main St Apt 4B, Springfield, IL 62704');
$parser->getStreetNumber(); // '123'
$parser->getStreetName(); // 'Main'
$parser->getRouteType(); // 'St'
$parser->getUnit(); // 'Apt 4B'
$parser->getCity(); // 'Springfield'
$parser->getStateCode(); // 'IL'
$parser->getStateName(); // 'Illinois'
$parser->getPostalCode(); // '62704'
$parser->getCountry(); // 'US'
Separate the parts with a comma, semicolon, tab or newline — all four delimit, so a one-line address and a
mailing-label one parse the same way. The unit can sit on the street segment or stand on its own, so 123 Main St Apt 4B, Springfield, IL 62704 and 123 Main St, Apt 4B, Springfield, IL 62704 give the same
result.
A leading or trailing directional is recognized and kept apart from the street name. getStreetName()
includes it by default; pass false for the bare name:
use Pop\Parser\Address\AddressParser;
$parser = new AddressParser();
$parser->parse('456 N Elm Street, Chicago, IL 60601');
$parser->getDirection(); // 'N'
$parser->getStreetName(); // 'N Elm'
$parser->getStreetName(false); // 'Elm'
$parser->getRouteType(); // 'Street'
PO boxes are matched in all the forms people write them — PO Box 1234, P.O. Box 1234, POB 1234,
Box 1234. The box lands in getStreetName(), getStreetNumber() stays null, and isPoBox() says
which kind of address you have:
use Pop\Parser\Address\AddressParser;
$parser = new AddressParser();
$parser->parse('PO Box 1234, Springfield, IL 62704');
$parser->isPoBox(); // true
$parser->getStreetName(); // 'PO Box 1234'
$parser->getStreetNumber();// null
$parser->getCity(); // 'Springfield'
Canadian addresses parse without a flag — the province is resolved the same way a state is, and
getCountry() reports 'CA'. The postal code comes back with its space removed, so H3Z 2Y7 is
stored as H3Z2Y7 and needs reformatting before it goes on a label:
use Pop\Parser\Address\AddressParser;
$parser = new AddressParser('55 Rue Principale, Montreal, QC H3Z 2Y7');
$parser->parse();
$parser->getStateName(); // 'Quebec'
$parser->getStateCode(); // 'QC'
$parser->getPostalCode(); // 'H3Z2Y7'
$parser->getCountry(); // 'CA'
A US ZIP+4 splits across two fields rather than staying in one, which is what a database with separate columns wants:
use Pop\Parser\Address\AddressParser;
$parser = new AddressParser('123 Main St, Springfield, IL 62704-1234');
$parser->parse();
$parser->getPostalCode(); // '62704'
$parser->getZip4(); // '1234'
$parser->hasZip4(); // true
getFullAddress() puts it back together, and its three arguments control the delimiter, whether the
state appears as a code or a full name, and whether the country is appended:
use Pop\Parser\Address\AddressParser;
$parser = new AddressParser('123 Main St Apt 4B, Springfield, IL 62704');
$parser->parse();
$parser->getFullAddress();
// '123 Main St, Apt 4B, Springfield, IL 62704'
$parser->getFullAddress(', ', false, true);
// '123 Main St, Apt 4B, Springfield, Illinois 62704, US'
Casting to a string is getFullAddress() with its defaults, and toArray() returns all eleven fields.
As with names, every getter has a has*() companion.
A parser is reusable: pass a new string to parse() and it replaces both the parsed fields and the stored
data, so a later bare parse() re-parses the string you last gave it.
Reference Data#
The lookup tables the parsers work from are public, which is what you want when a form has to validate against the same data the parser will later accept. Both classes are instantiated, not static:
use Pop\Parser\Address\AddressValues;
use Pop\Parser\Name\NameValues;
$values = new AddressValues();
$values->getStates(); // ['AL' => 'Alabama', 'AK' => 'Alaska', ...] — 52 US entries
$values->getStates('CA'); // the 13 Canadian provinces and territories
$values->getStateCodes(); // the keys alone
$values->getCommonRouteTypes();// the 38 everyday route types
$values->getRouteTypes(); // all 503, mapping each spelling to its abbreviation
$values->getDirections();
$values->getUnitTypes();
$names = new NameValues();
$names->getSalutations(); // ['mr' => 'Mr.', 'master' => 'Mr.', ...]
$names->getSuffixes();
$names->getLastnamePrefixes();
$names->getNicknameDelimiters();
getStates(), getStateCodes() and getStateNames() take a country of 'US' or 'CA', defaulting to
'US'. getSalutations() is a map — several spellings point at one canonical form — so populate a select
from array_unique() over its values.
See Also#
- Forms — validating the string before you hand it to a parser
- Records & the ORM — storing the parsed fields in their own columns
- Utilities & Helpers —
Pop\Utils\Strfor the case and slug conversions around them - pop-parser README — every getter on both parsers