nameparser parses human names into seven fields — title, given, middle, family, suffix, nickname, maiden. Results are immutable, configuration is composable, and locale packs are opt-in.
📣 nameparser 3.0 removes HumanName and the rest of the 1.x
compatibility layer. HumanName, Constants, the shared
CONSTANTS and nameparser.util are gone, along with the 1.x
names of the word lists; parse() and Parser are the
replacement. 2.8 is the last release that has them, and it warns at
each use 3.0 removes; Coming from 1.x or 2.x below says where to
start. 3.0 also configures a Lexicon by reading
(Lexicon.default().add("leed", kind="credential")), renders a name
in the order it was written (str(parse("김민준")) is '김민준'),
and adds packs that choose the languages a parse reads. The release log has
the details. Please open an
issue for anything
that parses wrong.
Chinese, Japanese and Korean names written in their own scripts are read family-first, unspaced Korean names are split against the census surname list, and CJK honorifics are recognized. See East Asian names.
pip install nameparser
Requires Python 3.11+.
>>> from nameparser import parse
>>> name = parse("Dr. Juan Carlos García de la Vega III (Juanca)")
>>> name
<ParsedName: [
title: 'Dr.'
given: 'Juan'
middle: 'Carlos García'
family: 'de la Vega'
suffix: 'III'
nickname: 'Juanca'
]>
>>> name.family_base, name.family_particles
('Vega', 'de la')A Spanish name usually ends in two family names, the father's first and the mother's second. Out of the box the parser reads one family name, with the words between it and the given name as middle names. The Spanish pack reads the two family names and gives each its own view:
>>> from nameparser import Parser, Policy, locales, parser_for
>>> spanish = parser_for(locales.ES)
>>> juan = spanish.parse("Dr. Juan Carlos García de la Vega III (Juanca)")
>>> juan.middle, juan.family
('Carlos', 'García de la Vega')
>>> juan.surname1, juan.surname2, juan.generation
('García', 'de la Vega', 'III')
>>> juan.render("{family}, {given}")
'García de la Vega, Juan'Juan Carlos may also be one compound given name. Nothing in the text says which, so reading it that way is a switch for data you know is written so:
>>> compound = parser_for(locales.ES,
... base=Parser(policy=Policy(two_given_names=True)))
>>> compound.parse("Juan Carlos García de la Vega").given
'Juan Carlos'Most packs choose languages, and a choice turns on the readings the
chosen language holds and the default leaves off. Lady is a British
title and, in Spanish-speaking Latin America, a given name; the Spanish
choice reads the given name, the title staying one inside a phrase:
>>> parse("Lady Heidenreich").title
'Lady'
>>> spanish.parse("Lady Heidenreich").given
'Lady'
>>> spanish.parse("Lady Justice Jane Smith").title
'Lady Justice'A strict choice reads only the chosen languages' words, the words every language shares, and words written in a script other than Latin, so the English title phrase is no longer one:
>>> strict = parser_for(locales.ES, strict=True)
>>> strict.parse("Lady Justice Jane Smith").title
''A pack can also take a reading out. Vietnamese written without its
diacritics meets the Dutch particle van, which chains onto the given
name under a family-first order. The Vietnamese pack reads family-first
and removes the particle reading, so Van stays a middle name:
>>> from nameparser import FAMILY_FIRST_GIVEN_LAST
>>> ordered = Parser(policy=Policy(name_order=FAMILY_FIRST_GIVEN_LAST))
>>> ordered.parse("Nguyen Van Anh").given # van, Dutch, chains on
'Van Anh'
>>> vietnamese = parser_for(locales.VI)
>>> anh = vietnamese.parse("Nguyen Van Anh")
>>> anh.family, anh.middle, anh.given
('Nguyen', 'Van', 'Anh')More shapes the parser reads:
>>> parse("The Rt Hon Sir John Smith KCB MP").title # a run of titles
'The Rt Hon Sir'
>>> parse("Dean Smith").given # alone, Dean is a given name
'Dean'
>>> parse("Associate Dean Jane Smith").title # in a title phrase, a title
'Associate Dean'
>>> listed = parse("Smith, John V., Jr., MD, PhD") # listing form
>>> listed.middle, listed.generation, listed.credentials
('V.', 'Jr.', 'MD, PhD')
>>> parse("Jack MA").suffix # capitals mark a credential
'MA'
>>> parse("Jack Ma").family # and a surname
'Ma'
>>> dutch = parse("Berg, Jan van der") # Dutch index form, particles last
>>> dutch.given, dutch.family
('Jan', 'van der Berg')
>>> parse("Van Johnson").ambiguities # a guess is reported
(Ambiguity('particle-or-given': 'Van'),)
>>> van = parse("Ludwig van Beethoven").tokens[1]
>>> van.reading.languages # the vocabulary that read "van"
('nl',)
>>> parse("김민준").family # Korean: unspaced, split on the census list
'김'
>>> parse("高橋 みなみ").family # Japanese: kanji with kana, family first
'高橋'
>>> parse("김민준씨").honorifics # an honorific written against the name
'씨'
>>> parse("г-н Иван Петров").title # Cyrillic title
'г-н'
>>> arabic = parse("محمد بن سلمان") # Arabic: بن chains onto the family name
>>> arabic.family, arabic.patronymic # and marks it a patronymic
('بن سلمان', 'بن سلمان')
>>> parse("طارق عبد العزيز").family # عبد + a name of God is one name
'عبد العزيز'
>>> parse("نوال عبد هاشم").family # هاشم is not one, so it stands alone
'هاشم'
>>> chinese = parser_for(locales.ZH) # Han text does not say which language
>>> chinese.parse("毛泽东").family # so splitting it is opt-in
'毛'
>>> parse("Сидоров Иван Петрович").given # read given-first by default
'Сидоров'
>>> russian = parser_for(locales.RU) # the Russian pack reads the patronymic
>>> ivan = russian.parse("Сидоров Иван Петрович")
>>> ivan.given, ivan.patronymic, ivan.family
('Иван', 'Петрович', 'Сидоров')
>>> locales.available()
('bn', 'cs', 'es', 'es_ar', 'ga', 'gd', 'hi', 'hr', 'ja', 'ne', 'pt', 'pt_br', 'ru', 'sk', 'sl', 'tr_az', 'vi', 'zh')Each reading comes from a word's readings in the vocabulary or from a
Policy setting, and you can change both. Ask the vocabulary what a word
may be read as, then add or remove readings and hand the new Lexicon
to a Parser:
>>> from nameparser import Lexicon
>>> [r.kind for r in Lexicon.default().readings_of("dean")]
['office', 'given', 'family']
>>> deans = Lexicon.default().remove("dean", kind="given") # Dean is always a title
>>> Parser(lexicon=deans).parse("Dean Smith").title
'Dean'
>>> leed = Lexicon.default().add("leed", "ap", kind="credential")
>>> Parser(lexicon=leed).parse("John Smith LEED AP").suffix
'LEED AP'A Policy says how positions are read, such as which name comes
first:
>>> from nameparser import FAMILY_FIRST
>>> hungarian = Parser(policy=Policy(name_order=FAMILY_FIRST))
>>> nagy = hungarian.parse("Nagy Ádám")
>>> nagy.given, nagy.family
('Ádám', 'Nagy')A Lexicon and a Policy are frozen, so each change returns a new
object and nothing is shared between parsers.
- Using the parser — the full tour: input shapes, aggregates, rendering, comparison, ambiguities, tokens
- Customizing the parser — vocabulary, behavior, and presentation
- Locale packs — opt-in bundles for East Slavic patronymics, Turkic markers, and more
- There's also a CLI:
python -m nameparser --json "Doe, John"
Measured 2026-11-05 against the 3.0 development tree, by comparing each reading with the boxes the name was filed in. That is agreement with someone else's convention, not ground truth, after folding case, periods, commas and spacing:
- US patent inventors (PatentsView, 657,991 distinct name-and-country records, split into two boxes by the filing attorney): both boxes agree for 94.7%, and for 98.0% outside Spanish- and Portuguese-speaking countries.
- UK company filings (people with significant control, 1,039,144 records typed into title, forename, middle and surname boxes): all four agree for 96.8%.
- Czech election candidates (170,181, with degrees before and after
the name): all four boxes agree for 97.0%, and for 97.5% with
locales.CS.
Most of what the default misses is a convention rather than a misreading.
It reads one family name, so a Spanish double surname comes out differently
from how its bearer files it. Choosing the language closes most of the gap:
for ORCID researchers in Spain, parser_for(locales.ES) lifts agreement
from 49.5% to 96.7% (Mexico 33.6% to 96.9%). The pack costs where people
file a single surname: Argentine patent inventors agree 93.8% by default,
86.2% under ES and 92.7% under ES_AR.
3.0 has no HumanName: parse(text) reads the same seven fields,
named given and family where HumanName had first and
last, and a Lexicon and Policy handed to a Parser
replace Constants. Upgrade to 2.8.2 first and run your tests under
python -W error::DeprecationWarning: it stops at every use 3.0
removes except a read of the shared CONSTANTS or of a Lexicon
set field and the imports Migrating to 3.0 lists, which 2.8.2 does
not warn on, so search for those too. A pickled HumanName or
Constants does not load in 3.0; store parse(text).as_dict() or
the original string instead.
Migrating to 3.0 maps HumanName's attributes and the
Constants settings onto the 3.0 API.
LGPL licensed. See LICENSE for details.