{"id":50962790,"url":"https://github.com/iliaal/nameparser","last_synced_at":"2026-06-18T16:30:34.961Z","repository":{"id":363169851,"uuid":"1262195288","full_name":"iliaal/nameparser","owner":"iliaal","description":"Casing- and credential-aware PHP full-name parser. Fork of theiconic/name-parser, tuned for professional/clinician names.","archived":false,"fork":false,"pushed_at":"2026-06-07T18:42:52.000Z","size":72,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-06-07T19:20:47.253Z","etag":null,"topics":["credentials","fullname","human-names","name-parser","name-parsing","parser","php","text-processing"],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/iliaal.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-07T17:36:25.000Z","updated_at":"2026-06-07T18:42:56.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/iliaal/nameparser","commit_stats":null,"previous_names":["iliaal/nameparser"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/iliaal/nameparser","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iliaal%2Fnameparser","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iliaal%2Fnameparser/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iliaal%2Fnameparser/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iliaal%2Fnameparser/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/iliaal","download_url":"https://codeload.github.com/iliaal/nameparser/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iliaal%2Fnameparser/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34499403,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-18T02:00:06.871Z","response_time":128,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["credentials","fullname","human-names","name-parser","name-parsing","parser","php","text-processing"],"created_at":"2026-06-18T16:30:33.279Z","updated_at":"2026-06-18T16:30:34.955Z","avatar_url":"https://github.com/iliaal.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# iliaal/nameparser\n\n[![CI](https://github.com/iliaal/nameparser/actions/workflows/ci.yml/badge.svg)](https://github.com/iliaal/nameparser/actions/workflows/ci.yml)\n[![Latest Version](https://img.shields.io/packagist/v/iliaal/nameparser)](https://packagist.org/packages/iliaal/nameparser)\n[![PHP Version](https://img.shields.io/packagist/php-v/iliaal/nameparser)](https://packagist.org/packages/iliaal/nameparser)\n[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)\n[![Follow @iliaa](https://img.shields.io/badge/Follow-@iliaa-000000?style=flat\u0026logo=x\u0026logoColor=white)](https://x.com/intent/follow?screen_name=iliaa)\n\nParse a string containing a full name into its parts (salutation, first name,\nmiddle names, initials, last name with prefixes, suffix, nickname).\n\n\u003e **Fork lineage.** This is a fork of\n\u003e [theiconic/name-parser](https://github.com/theiconic/name-parser) (dormant\n\u003e since ~2020), built on top of the modernization done by\n\u003e [codebyzach/name-parser](https://github.com/CodeByZach/name-parser). It adds\n\u003e **casing- and credential-aware parsing** and a **confidence/ambiguity signal**,\n\u003e and targets PHP 8.3+.\n\n## Why this fork\n\nThe upstream parser keys every token through `strtolower()` before matching it\nagainst its salutation/suffix dictionaries, so it cannot tell an all-caps\ncredential from a same-spelled name. Two failure modes follow, both common in\nprofessional and clinician name lists:\n\n1. A trailing credential without a comma swallows the surname:\n   `\"Jane Doe DDS\"` parsed to last name **\"Dds\"** (the real surname lost).\n2. A short credential token that is also a real name is mis-stripped:\n   the Vietnamese surname **\"Do\"** and given name **\"Vi\"** were consumed as the\n   credentials DO / VI.\n\nThis fork fixes both and adds an advisory confidence pass for the genuinely\nambiguous cases.\n\n### What changed\n\n- **Casing as a signal.** An ambiguous token (`Do`, `Vi`, `Ma`, roman numerals,\n  two-letter credentials) is treated as a credential only when written ALL-CAPS\n  (`DO`, `VI`); Title- or lower-case keeps it as a name part. People write\n  credentials in caps and names in title case, so the original casing carries\n  the signal that lowercasing discarded.\n- **Terminal-token guard.** A lone name-colliding token in a comma given-name\n  segment is kept as a name rather than emptied into a credential, unless its\n  casing reads as a credential.\n- **Confidence assessor.** When a token matches a credential but the casing is\n  uninformative (uniform-case input, or a lowercase token), `Confidence::assess()`\n  flags the input so you can route it to manual review instead of trusting the\n  split.\n- **Expanded English dictionary** (inherited from the CodeByZach fork): DDS, DO,\n  DVM, PsyD, LCSW, MSW, MBA, EMBA, Esq, roman numerals VI to X, `Hon.`, and more.\n- **Nursing and allied-health credentials.** RN, NP, PharmD, APRN, PA-C, OTR/L,\n  and 30+ more, mined by frequency from the NPI registry, so a trailing\n  credential no longer leaks into the first name.\n- **Unclosed nickname delimiter.** An opening `(` or quote with no matching\n  close no longer swallows the surname (`\"John (Bob Smith\"` keeps `Smith`).\n\n## Requirements\n\n- PHP 8.3+ (tested through 8.5)\n- `ext-mbstring`\n\n## Installation\n\n```bash\ncomposer require iliaal/nameparser\n```\n\n## Usage\n\n```php\nuse Iliaal\\NameParser\\Parser;\n\n$parser = new Parser();\n$name = $parser-\u003eparse('Dr. Jane A. Doe DDS');\n\n$name-\u003egetSalutation();   // \"Dr.\"\n$name-\u003egetFirstname();    // \"Jane\"\n$name-\u003egetInitials();     // \"A.\"\n$name-\u003egetLastname();     // \"Doe\"\n$name-\u003egetSuffix();       // \"DDS\"\n$name-\u003egetFullName();     // \"Jane A. Doe\"\n```\n\nThe full getter surface (`getMiddlename()`, `getNickname()`, `getLastnamePrefix()`,\n`getGivenName()`, `getAll()`) is unchanged from upstream.\n\n### Structured output\n\n`toArray()` returns every part under a fixed key set, with an empty string for\nany part that is absent. Unlike `getAll()`, which omits empty parts and varies\nits keys, this shape is safe to consume without existence checks:\n\n```php\n$parser-\u003eparse('Dr. Jane A. Doe DDS')-\u003etoArray();\n// [\n//   'salutation' =\u003e 'Dr.', 'firstname' =\u003e 'Jane', 'initials' =\u003e 'A.',\n//   'middlename' =\u003e '', 'lastname_prefix' =\u003e '', 'lastname' =\u003e 'Doe',\n//   'suffix' =\u003e 'DDS', 'nickname' =\u003e '', 'given_name' =\u003e 'Jane A. Doe',\n//   'full_name' =\u003e 'Jane A. Doe',\n// ]\n```\n\n### Confidence / ambiguity\n\nFor batch imports where a wrong split is a data-integrity problem, check whether\nthe input was decidable from its casing. The signal is available two ways: as a\nstandalone pre-check on a raw string, or on the parsed result itself.\n\n```php\nuse Iliaal\\NameParser\\Confidence;\n\n// pre-check, before parsing\n$result = Confidence::assess('NGUYEN, VI');\n// ['ambiguous' =\u003e true, 'notes' =\u003e [\"'VI' could be a name or a credential; input casing is uniform\"]]\n\n// or read it off the parse; same signal, derived from the same input\n$result = $parser-\u003eparse('NGUYEN, VI')-\u003egetConfidence();\n\nif ($result['ambiguous']) {\n    // queue the row for manual review instead of trusting the parse\n}\n```\n\n`getConfidence()` is read-only and does not change what `parse()` returns; it is\nan advisory pass you opt into. A mixed-case input like `\"Nguyen, Vi\"` stays\nunflagged; the title-case `Vi` resolves to the given name.\n\n\u003e **All-caps limitation.** Disambiguation keys off casing, so uniform-case input\n\u003e (all-caps legacy and registry data, or all-lowercase) carries no signal: an\n\u003e ambiguous trailing token reads as a credential by default. The confidence pass\n\u003e flags these when the token plausibly collides with a real name (`Do`, `Vi`,\n\u003e `Ma`, roman numerals, `MBA`), so you can route them to review. Clean\n\u003e credentials that are not also names (`RN`, `PT`, `OD`) are left unflagged to\n\u003e keep review volume manageable on all-caps datasets.\n\n## Development\n\n```bash\ncomposer install\ncomposer test     # phpunit\ncomposer analyse  # phpstan (level 9)\ncomposer lint     # php-cs-fixer (dry run)\n```\n\n## Credits\n\nOriginal library by [The Iconic](https://github.com/theiconic). Modernization to\nPHP 8.3+ by [Zachary Miller](https://github.com/CodeByZach). Casing/credential\nparsing and confidence signal in this fork by Ilia Alshanetsky.\n\n## License\n\nMIT. See [LICENSE](LICENSE). Upstream copyright notices are retained.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Filiaal%2Fnameparser","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Filiaal%2Fnameparser","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Filiaal%2Fnameparser/lists"}