Skip to content

1.4.0

Choose a tag to compare

@iliaal iliaal released this 04 Aug 14:33
· 63 commits to master since this release
1.4.0
64ed0b1

Added

  • Joint salutations parse as one honorific, so Mr. and Mrs. Brad Smith keeps Brad as the first name instead of reading the connector as one (Mr. & Mrs. normalizes to the same value). Any pairing works (Dr. and Mrs., Ms. & Ms.), and the connector needs a title on both sides, so Mr. and Brad Smith is left alone. Fixes #4.
  • Name::isJoint() reports a name whose honorific covers two people, for callers importing households. The parsed given and family name belong to the person actually named. Only the title-anchored form is detected: a bare Brad and Jane Smith has no honorific to anchor the connector and reports false.
  • Name::getSalutations() returns the honorific split one entry per person addressed, so a contact record with a single prefix field can take the first: Mr. and Mrs. Brad Smith gives ['Mr.', 'Mrs.'], and the partner is that second title plus getLastname(). Stacked titles for one person stay in one entry (Rev. Dr John Doe gives ['Rev. Dr.']), and a name with no honorific gives an empty list.
  • Name::getPartner() returns the second person a joint honorific addresses as a Name of her own, so a household import can build the partner contact without assembling strings: Mr. and Mrs. Brad Smith gives a partner with salutation Mrs. and lastname Smith. A particle surname crosses over whole (van der Berg); the given name, initials and any credential stay with the person actually named. Returns null when the honorific covers one person.
  • Irish surname particles Ó, Ní, Nic, Uí, Ua, and Mhic, so Éamon Ó Cuív keeps Ó Cuív as the surname instead of reading Ó as a middle initial. They render capitalised, unlike the continental particles, and the fada survives uniform-caps input (ÉAMON Ó CUÍV → Ó Cuív). Only the fada-bearing Ó counts: anglicised Eamon O Cuiv is indistinguishable from a middle initial (John F Kennedy), so bare O stays an initial.
  • English honorifics Dame, Lady, Lord, Pastor, Professor, Reverend, and Rt Hon (Lord Ashcroft → salutation Lord, surname Ashcroft). Rt Hon also matches its abbreviated and article-led forms (Rt. Hon. Boris Johnson, The Rt Hon Boris Johnson).

Changed

  • Confidence::assess() flags a two-token input led by an honorific that is also a real name (Lord Ashcroft, Pastor Gonzalez, Hon Chan), where the title reading leaves no given name and nothing in the input decides between the two. A comma resolves it structurally (Lord, Jack) and a third token leaves a given name either way (Lady Diana Spencer), so neither is flagged.
  • parse() and standalone Confidence::assess() now reject inputs over 1,048,576 bytes or 65,536 non-empty tokens with LengthException before structural allocation.
  • setMaxCombinedInitials() now accepts only 0 through 64 and combined-token expansion is capped at 131,072 output parts per parse, preventing hostile configuration from creating an unbounded part list. Nickname delimiter configuration is similarly bounded to 32 pairs of at most 64 bytes each.
  • Large runs of combined initials, repeated salutations, and surname-first honorifics now parse in linear time instead of repeatedly reindexing the token array.
  • Comma-heavy malformed input no longer retains duplicate segment projections, cutting peak working memory for a 1 MB row from hundreds of megabytes to a linear bound.
  • Maximum-size interior tokens no longer materialize an array containing every grapheme, so a valid 1 MB row stays within a 32 MB PHP memory limit.
  • Camelcase detection remains linear without PCRE JIT at the 1,024-byte boundary, and maximum-size common-prefix nickname-delimiter configurations no longer multiply the structural-comma scan.
  • A pure all-caps unknown-candidate segment with no prior dictionary anchor is kept as a name rather than promoted to a suffix when a later credential appears (Smith, JOHN, MD → first John, suffix MD). Unknown candidates still ride after a known credential (MD, FACS) and peel from a mixed segment onto a later dictionary segment (John FACS, MD). Prefer Smith, MD, FACS when the unknown stands alone before the known credential.
  • getConfidence() now uses the parser's configured suffixes, salutations, and token boundaries. Standalone Confidence::assess($string) retains English defaults.

Fixed

  • A conjunction the honorific could not absorb is no longer title-cased into a name part, so Andrew and Sally Smith reports the middle name Sally instead of And Sally, and Mr. and Brad Smith reports the first name Brad instead of And. A title directly after such a conjunction addresses a second person, so it is dropped from the getters too (Mr. Andrew and Mrs Sally Smith no longer carries Mrs as a middle name). Both are marked as Part\Ignored, which no getter exports, so the text is still reachable through Name::getParts(). The parser still does not identify the second person: isJoint() and getPartner() need a title on both sides of the conjunction, and the second given name stays where it lands.
  • Every word of an unattributed multi-word title is ignored after a conjunction, so Mr. Andrew and His Honour Sally Smith keeps only Sally as the middle name.
  • A leading credential in a comma given-name segment no longer authorizes a later uppercase given name as an unknown credential (Smith, MD John PAUL keeps middle name Paul and suffix MD).
  • Name::isJoint() now requires two non-empty salutation groups rather than reporting true for a manually constructed orphan connector.
  • Invalid-UTF-8 confidence input now enforces the same 65,536-token ceiling before returning its ambiguity note.
  • A two-letter surname particle written in caps inside mixed-case input is no longer shredded into initials, so Jean DE Vries keeps de Vries and Mary LE Blanc keeps le Blanc instead of reporting initials D E and L E with the particle dropped. Three-letter particles were never affected (VON exceeds the combined-initial limit).
  • Decomposed Unicode accents stay attached to their base letter during casing, initial splitting, and short-surname detection.
  • Credentials before a trailing nickname are retained in both Western and comma forms.
  • German-only and other custom language dictionaries no longer throw when an English ambiguous suffix key is absent.
  • Comma-separated credential tails now drop punctuation and Unknown placeholders under the same rules as space-separated tails.
  • Nickname delimiters ignored by the 32-pair and 64-byte limits no longer shield structural commas.
  • Every stock mapper now accepts sparse integer-keyed input under its public array contract.
  • Custom SuffixMapper subclasses can override the protected uppercase check for ambiguous credentials again.
  • Canonical mixed-case credentials such as LAc and L.Ac. are recognized without making the title-case name Lac ambiguous.
  • Comma parsing once again dispatches through the protected parseSplitName() extension hook.
  • Caller-owned mapper objects retain their dictionaries and state after parser configuration changes, and sparse custom mapper output is normalized before the next mapper runs.
  • Invalid UTF-8 is reported as ambiguous by Confidence::assess(), and repeated ambiguity reasons are emitted once.
  • Pure lastname export includes consumer subclasses of Lastname without folding LastnamePrefix into the value.
  • Stacked and joint salutations use the same named-person boundary in comma and surname-first forms; nickname- or credential-only tails do not satisfy that boundary.
  • A salutation that is also a real name no longer swallows the comma form's surname segment, so Lord, Jack keeps Lord as the surname (previously it became a salutation and the surname was dropped entirely). This also covers the pre-existing Master, John and Hon, John. An unambiguous title is unchanged: Dr., John still reads as a salutation.
  • A dictionary salutation that follows a real name token stays part of the name rather than being promoted and dropped from the getters, so John Lord Smith Jr keeps Lord as the middle name and Blair, Kathleen MASTER OF SOCIAL WOR no longer reports a Mr. salutation. Only a leading article may sit before an honorific (The Rev. Mark Williams); an explicit setMaxSalutationIndex() still scans past leading name tokens.
  • Comma credentials retain source order, and an unknown all-caps candidate cannot cross a preserved name segment to consume a given name.
  • Custom unclosed nickname delimiters are removed exactly without ltrim() character-mask warnings, and nested delimiters use stack semantics so a mismatched closer cannot terminate an outer nickname span.
  • Comma and surname-first subparsers honor custom whitespace, and parsed confidence uses the parser's configured suffix dictionaries.
  • Segment sub-parsers inherit nickname delimiters, so a custom multi-character pair shields commas on the left segment when a structural comma follows (John %%Bob, Jr%% Smith, MD).
  • Surname-side nicknames are extracted when the given segment is a real name (John (Bob) Smith, Jane).
  • setWhitespace('') no longer leaves empty tokens that pollute getGivenName() / full_name with a stray space on double-spaced input.
  • Empty nickname closer strings are dropped with empty openers, so invalid delimiter config degrades to a no-op instead of an unclosable span.
  • Uniform-uppercase detection on comma input splits on commas as well as whitespace, so comma-dense rows do not force a full-string Unicode letters scan.
  • Comma-separated non-empty segments count toward the parser's 65,536-token ceiling.
  • Credential-only comma tails no longer reinterpret given names such as Della and Van as surname particles.
  • A quoted nickname whose closing quote immediately precedes a structural comma stays intact.
  • Connector-heavy salutation input is validated in linear time, and title-only connector chains no longer create a phantom joint partner.
  • Joint honorifics retain a terminal title-colliding shared surname (Mr. and Mrs. Lord) while still rejecting multi-word and connector-led title-only chains.
  • Promoted stock mapper pipelines refresh surname-particle dictionaries after a mutable language configuration changes.
  • Negative setMaxSalutationIndex() values now use the same leading-title semantics as the default value 0.
  • Caller-supplied confidence tokens no longer bypass the byte or token ceilings.

For contributors

  • CI now enforces the README punctuation rule, rejects empty PHPUnit suites, deprecations, notices, skipped tests, and incomplete tests, and no longer carries the obsolete mbstring-absence mock dependency.
  • composer analyse enforces the empty PHPStan baseline before running level 9 analysis, matching CI.