A simple Python module for parsing human names into their individual components

Overview

Name Parser

Build Status PyPI PyPI version Documentation

A simple Python (3.2+ & 2.6+) module for parsing human names into their individual components.

  • hn.title
  • hn.first
  • hn.middle
  • hn.last
  • hn.suffix
  • hn.nickname
  • hn.surnames (middle + last)

Supported Name Structures

The supported name structure is generally "Title First Middle Last Suffix", where all pieces are optional. Comma-separated format like "Last, First" is also supported.

  1. Title Firstname "Nickname" Middle Middle Lastname Suffix
  2. Lastname [Suffix], Title Firstname (Nickname) Middle Middle[,] Suffix [, Suffix]
  3. Title Firstname M Lastname [Suffix], Suffix [Suffix] [, Suffix]

Instantiating the HumanName class with a string splits on commas and then spaces, classifying name parts based on placement in the string and matches against known name pieces like titles and suffixes.

It correctly handles some common conjunctions and special prefixes to last names like "del". Titles and conjunctions can be chained together to handle complex titles like "Asst Secretary of State". It can also try to correct capitalization of names that are all upper- or lowercase names.

It attempts the best guess that can be made with a simple, rule-based approach. Its main use case is English and it is not likely to be useful for languages that do not conform to the supported name structure. It's not perfect, but it gets you pretty far.

Installation

pip install nameparser

If you want to try out the latest code from GitHub you can install with pip using the command below.

pip install -e git+git://github.com/derek73/python-nameparser.git#egg=nameparser

If you need to handle lists of names, check out namesparser, a compliment to this module that handles multiple names in a string.

Quick Start Example

>>> from nameparser import HumanName
>>> name = HumanName("Dr. Juan Q. Xavier de la Vega III (Doc Vega)")
>>> name
<HumanName : [
    title: 'Dr.'
    first: 'Juan'
    middle: 'Q. Xavier'
    last: 'de la Vega'
    suffix: 'III'
    nickname: 'Doc Vega'
]>
>>> name.last
'de la Vega'
>>> name.as_dict()
{'last': 'de la Vega', 'suffix': 'III', 'title': 'Dr.', 'middle': 'Q. Xavier', 'nickname': 'Doc Vega', 'first': 'Juan'}
>>> str(name)
'Dr. Juan Q. Xavier de la Vega III (Doc Vega)'
>>> name.string_format = "{first} {last}"
>>> str(name)
'Juan de la Vega'

The parser does not attempt to correct mistakes in the input. It mostly just splits on white space and puts things in buckets based on their position in the string. This also means the difference between 'title' and 'suffix' is positional, not semantic. "Dr" is a title when it comes before the name and a suffix when it comes after. ("Pre-nominal" and "post-nominal" would probably be better names.)

>>> name = HumanName("1 & 2, 3 4 5, Mr.")
>>> name
<HumanName : [
    title: ''
    first: '3'
    middle: '4 5'
    last: '1 & 2'
    suffix: 'Mr.'
    nickname: ''
]>

Customization

Your project may need some adjustment for your dataset. You can do this in your own pre- or post-processing, by customizing the configured pre-defined sets of titles, prefixes, etc., or by subclassing the HumanName class. See the full documentation for more information.

Full documentation

Contributing

If you come across name piece that you think should be in the default config, you're probably right. Start a New Issue and we can get them added.

Please let me know if there are ways this library could be structured to make it easier for you to use in your projects. Read CONTRIBUTING.md for more info on running the tests and contributing to the project.

GitHub Project

https://github.com/derek73/python-nameparser

Comments
  • Feature: Add first and middle name(s) initials

    Feature: Add first and middle name(s) initials

    Initials can be quite important when comparing two names in order to determine whether they are the same or not. I have added a property to HumanName called initials which holds the first letters of the first name and the middle names. The list-version of the property is a list of single characters. The string-version is build from the list and has a dot and space after each character.

    Some examples:

    >>> HumanName("John Doe")
    <HumanName : [
    	title: '' 
    	initials: 'J.' 
    	first: 'John' 
    	middle: '' 
    	last: 'Doe' 
    	suffix: ''
    	nickname: ''
    ]>
    >>> HumanName("Dr. Juan Q. Xavier Velasquez y Garcia")
    <HumanName : [
    	title: 'Dr.' 
    	initials: 'J. Q. X.' 
    	first: 'Juan' 
    	middle: 'Q. Xavier' 
    	last: 'Velasquez y Garcia' 
    	suffix: ''
    	nickname: ''
    ]>
    >>> HumanName("Doe, John Boris D.")
    <HumanName : [
    	title: '' 
    	initials: 'J. B. D.' 
    	first: 'John' 
    	middle: 'Boris D.' 
    	last: 'Doe' 
    	suffix: ''
    	nickname: ''
    ]>
    >>> HumanName("Doe, John Boris D.").initials
    'J. B. D.'
    >>> HumanName("Doe, John Boris D.").initials_list
    ['J', 'B', 'D']
    

    Since the property is derived from the first and middle names, it will not be counted in the len function nor will it be displayed in the str function.

    Each time the first or middle names are updated using the setter, the initials are updated as well. The initial creation of the initials is executed in the post_process phase.

    I have added tests and updated the documentation where needed.

    I hope this pull request is in line with the quality requirements and vision of the library. The changes should be backwards compatible, but please let me know if I have missed anything!

    enhancement 
    opened by rinkstiekema 20
  • Parsing title and last name, e.g.

    Parsing title and last name, e.g. "Mr XXX" should be last name, not first name

    Love this library - very useful.

    However, I've noticed that parsing names in the format Prefix Lastname (e.g. Mr Magoo) parse with a blank name.last and the last name in the first name position (e.g. name.first == Magoo, name.last == ''). I think this should be the other way round!

    I may have time to fix this in your code later, but for now i'm using the following kludge to make it work in my code...

    if name.title != '': if name.last == '': name.last = name.first name.first = ''

    enhancement 
    opened by danhartropp 16
  • Wrong capitalized letter in Portuguese names

    Wrong capitalized letter in Portuguese names

    First of all, congrats for the great project.

    I have found a small issue related to Portuguese names. By running the following code:

    from nameparser import HumanName
    name = HumanName('joao da silva do amaral de souza')
    name.capitalize()
    str(name)
    

    I get the following result:

    'Joao da Silva Do Amaral de Souza'

    when it should be:

    'Joao da Silva do Amaral de Souza'

    The d from do should be lowercase.

    enhancement 
    opened by kelvins 10
  • Option to get None instead of empty string

    Option to get None instead of empty string

    Hey,

    is there an option to get None instead of an empty string for the components? E.g.

    >>> name = HumanName("1 & 2, 3 4 5, Mr.")
    >>> name.title
    None
    >>>name.first
    '3'
    
    enhancement 
    opened by Xennis 9
  • error on two joiner words

    error on two joiner words

    If a name contains two joiner words one after another, s.a. "John of the Doe", get: HumanName:ERROR:parser.py:Couldn't find 'The' in pieces. error.

    bug 
    opened by daryanypl 7
  • possibly incorrect parsing of

    possibly incorrect parsing of "grand"

    Just noticed that if I parse "Grand Rounds", it returns:

    >>> name
    <HumanName : [
    	title: 'Grand' 
    	first: '' 
    	middle: '' 
    	last: 'Rounds' 
    	suffix: ''
    	nickname: ''
    ]>
    

    Kinda odd no?

    enhancement wontfix probabilistic 
    opened by thehesiod 6
  • a few common special cases

    a few common special cases

    Sister Souljah -- "Sister" is more of a title than last name. His Holiness the Dalai Lama -- "His Holiness" -- the two words together is the title. Bob Jones, composer
    Bob Jones, author Bob Jones, compositeur -- (French for composer)

    Here's the code I used:

            name = HumanName('Sister Souljah')
            library_sort_name = u' '.join([name.first, name.middle, name.suffix, name.nickname, name.title])
            if name.last:
                library_sort_name = u''.join([name.last, ", ", library_sort_name])
            print "library_sort_name=%s" % library_sort_name
            
            name = HumanName('His Holiness the Dalai Lama')
            library_sort_name = u' '.join([name.first, name.middle, name.suffix, name.nickname, name.title])
            if name.last:
                library_sort_name = u''.join([name.last, ", ", library_sort_name])
            print "library_sort_name=%s" % library_sort_name
            
            name = HumanName('Bob Jones, author')
            library_sort_name = u' '.join([name.first, name.middle, name.suffix, name.nickname, name.title])
            if name.last:
                library_sort_name = u''.join([name.last, ", ", library_sort_name])
            print "library_sort_name=%s" % library_sort_name
            
            name = HumanName('Bob Jones, compositeur')
            library_sort_name = u' '.join([name.first, name.middle, name.suffix, name.nickname, name.title])
            if name.last:
                library_sort_name = u''.join([name.last, ", ", library_sort_name])
            print "library_sort_name=%s" % library_sort_name
    
    
    enhancement 
    opened by daryanypl 6
  • First name Van (which is also sometimes a prefix) not handled correctly

    First name Van (which is also sometimes a prefix) not handled correctly

    >>> from nameparser import HumanName
    ... HumanName('Van Nguyen')
    0: <HumanName : [
        title: '' 
        first: 'Van Nguyen' 
        middle: '' 
        last: '' 
        suffix: ''
        nickname: ''
    ]>
    >>> import nameparser
    >>> nameparser.VERSION
    1: (0, 3, 3)
    >>>
    
    bug 
    opened by htoothrot 6
  • Can't handle Japanese names

    Can't handle Japanese names

    name = nameparser.HumanName("鈴木太郎")

    name Traceback (most recent call last): File "", line 1, in UnicodeEncodeError: 'ascii' codec can't encode characters in position 36-39: ordinal not in range(128)

    Also: the concept of "last name" and "first name" isn't valid for Chinese, Japanese, Korean (CJK) names.

    bug 
    opened by pludemann 5
  • Judge-related titles not parsing

    Judge-related titles not parsing

    Hey -

    First off, awesome package. I've been working with a dataset of ~3000 judges and associated titles, and noticed nameparser doesn't pick most (well, any) of them up. Below is the filtered list with at least a few examples/variations on each. I'm happy to do the changes if you'd like. Let me know.

    common

    Magistrate Judge John F. Forster, Jr Magistrate Judge Joaquin V.E. Manibusan, Jr Magistrate-Judge Elizabeth Todd Campbell Mag-Judge Harwell G Davis, III Mag. Judge Byron G. Cudmore Chief Judge J. Leon Holmes Chief Judge Sharon Lovelace Blackburn Judge James M. Moody Judge G. Thomas Eisele Judge Callie V. S. Granade Judge C Lynwood Smith, Jr Senior Judge Charles R. Butler, Jr Senior Judge Harold D. Vietor Senior Judge Virgil Pittman
    Honorable Terry F. Moorer Honorable W. Harold Albritton, III Honorable Judge W. Harold Albritton, III Honorable Judge Terry F. Moorer Honorable Judge Susan Russ Walker Hon. Marian W. Payson Hon. Charles J. Siragusa

    rare

    US Magistrate Judge T Michael Putnam Designated Judge David A. Ezra Sr US District Judge Richard G Kopf

    enhancement 
    opened by end0 5
  • Ph.D., Esq., M.D., C.F.P., etc. are titles, not suffixes

    Ph.D., Esq., M.D., C.F.P., etc. are titles, not suffixes

    Moving the previous issue from the Google Code because I like the idea and would like to implement it, someday. Originally posted by jayqhacker, Feb 7, 2012.


    Ph.D., Esq., M.D. and other titles are classified as suffixes. This is perhaps convenient for parsing, since they appear at the end of a name, but they are in fact titles. A suffix distinguishes people and is part of your legal name; a title does not and (in most countries) is not. "J. Smith Jr." and "J. Smith Sr." are certainly different people, whereas "J. Smith", "J. Smith, PhD" and "J. Smith, MD" may or may not be.

    I propose titles end up in the .title field, and suffices end up in the .suffix field.

    Name parsing is a hard problem; ultimately I think you'd want a statistical, machine learning approach, but you can probably get pretty far with rules.

    The two issues are: 1) some suffixes are part of your name, some aren't; and 2) some titles come before your name, some after.

    You could solve both by splitting titles into pre- and post-titles, and making suffixes just ('jr','sr','2','i','ii','iii','iv','v').


    Project Member #3 derek73

    I played with adding a new list to keep track of titles that were added at the end. If we treat the suffixes as a definitive and complete list, then we can assume anything else is a title. The initials "i" and "v" are problematic, but we could probably assume that they are initials in the case of "John V".

    I like the idea of separating out the parts of the name that definitely signify another person, and your definition of suffix. Thinking about it, I guess a suffix always comes directly after the name? Like you wouldn't have "John Doe, Phd, Jr". Also the case of having 2 suffixes seems somewhat remote, e.g. "'Smith, John E, III, Jr'"? So I guess that would make the patterns look something like this.

    # no commas:      title first middle middle middle last suffix|title_suffix title_suffix
    # suffix comma:   title first middle last, suffix|title_suffix [, title_suffix]
    # lastname comma: last, title first middles[,] suffix|title_suffix [,title_suffix]
    
    SUFFIXES = set((
        'jr','sr','2','i','ii','iii','iv','v',
    ))
    
    TITLE_SUFFIXES = set((
        'phd','md','esquire','esq','clu','chfc','cfp',
    ))
    

    I got as far as finding that equality test would need to be updated. It got me wondering if perhaps we should change the equality test, per your example, to test that ' '.join(first, middle, last, suffix) are the same. Perhaps its easy enough for someone to test if unicode() representations are equal on their own if they want titles too. Or maybe that's too smart.


    That sounds like a reasonable approach. I don't personally use equality, but you might consider having it do the "dumb" least-surprise exact comparison, and adding a similarity method that returns a float in 0.0 - 1.0, eventually aiming for something like the probability that these two names reference the same person.

    Also, watch out for "King John V." ;)

    enhancement wontfix probabilistic 
    opened by derek73 5
  • Issue in names that contain comma(,) and has more than 3 words.

    Issue in names that contain comma(,) and has more than 3 words.

    Hi Derek, I have a usecase where I need to parse names containing comma(,), but the library seems to work differently in this case. from nameparser import HumanName as hm #1) here first name should be-E ANNE and lastname should be-LEONARDO hm("E Anne D,Leonardo") <HumanName : [ title: '' first: 'Leonardo' middle: '' last: 'E Anne D' suffix: '' nickname: '' ]>

    #2) here first name should be-Marry Ann and lastname should be-Luther hm("Mary Ann H,Luther") <HumanName : [ title: '' first: 'Luther' middle: '' last: 'Mary Ann H' suffix: '' nickname: '' ]>

    Even if I removed the comma from the name, it has different output.

    hm("Mary Ann H Luther") <HumanName : [ title: '' first: 'Mary' middle: 'Ann H' last: 'Luther' suffix: '' nickname: '' ]>

    opened by da-sbarde 1
  • Capitalizing Suffixes

    Capitalizing Suffixes

    I believe acronym-based suffixes are being incorrectly capitalized.

    > python3
    Python 3.8.10 (default, Jun 22 2022, 20:18:18) 
    [GCC 9.4.0] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import nameparser
    >>> nameparser.__version__
    '1.1.1'
    >>> n = nameparser.HumanName('GREGORY HOUSE M.D.')
    >>> n
    <HumanName : [
    	title: '' 
    	first: 'GREGORY' 
    	middle: '' 
    	last: 'HOUSE' 
    	suffix: 'M.D.'
    	nickname: ''
    ]>
    >>> n.capitalize()
    >>> n
    <HumanName : [
    	title: '' 
    	first: 'Gregory' 
    	middle: '' 
    	last: 'House' 
    	suffix: 'M.d.'
    	nickname: ''
    ]>
    >>> 
    
    

    I believe the suffix should be 'M.D.'

    bug 
    opened by DLu 0
  • output string formatting space before suffix if suffix does not exist

    output string formatting space before suffix if suffix does not exist

    I have this name: John Smith I'd like to reformat the name to look like this: Smith, John

    I've set the formatting I'd like to use:

    from nameparser.config import CONSTANTS
    CONSTANTS.string_format = "{last} {suffix}, {title} {first} ({nickname}) {middle}"
    

    The result I get is: Smith , John due to the space that precedes {suffix} in my string_format.

    However, I'd like the suffix to follow the last name if it ever occurs. Does your package allow for the trimming of space if no suffix exists, or should I implement this on my end?

    Apologies if this is already addressed in the documentation! Thank you!

    enhancement 
    opened by jocelynpender 0
  • Problem parsing name with , V

    Problem parsing name with , V

    nameparser version 1.1.1

    When I use HumanName with the string "John W. Ingram, V", it can't parse correctly but if I remove the comma, it works. Also, if I try using IV (4th) instead of V (5th), then it works with the comma so I think even though V seems to be recognized in the documentation, it isn't fully working.

    from nameparser import HumanName
    >>> name = HumanName("John W. Ingram, V")
    >>> name
    <HumanName : [
    	title: '' 
    	first: 'V' 
    	middle: '' 
    	last: 'John W. Ingram' 
    	suffix: ''
    	nickname: ''
    ]>
    >>> name = HumanName("John W. Ingram V")
    >>> name
    <HumanName : [
    	title: '' 
    	first: 'John' 
    	middle: 'W.' 
    	last: 'Ingram' 
    	suffix: 'V'
    	nickname: ''
    ]>
    
    
    bug 
    opened by pusateri 0
  • Weak Arabic Name handling

    Weak Arabic Name handling

    The library does not handle Arabic names well, even the most common patterns. I'm no expert on the topic, but I'm Arabic and know the common patterns.

    Compound Names My first name is "Mohamad Ali", but the library identifies "Ali" as my middle name. Arabic full names of the form "Mohamad X Surname" are almost always meant to have "Mohamad X" as a first name (with exceptions such as when X is "El" or "Al", in which case the surname is compound with the first word being "El" or "Al"). Other exceptions are "Bin" (the library handles these correctly). Examples: Mohamad Khalil, Mohamad Amin, Mohamad Ali, Mohamad El Amin, Mohamad Bin Salman, etc...

    Well-known Surname Suffixes Some names like "Mohamad Zeineddine" can be written as "Mohamad Zein El Dine". Here the first name is Mohamad and the surname is "Zein El Dine" which is equivalent to "Zeineddine". "El Dine"/"eddine" is an extremely common suffix to have in Arabic surnames (e.g. Zeineddine, Alameddine, Charafeddine, Safieddine, Saifeddine, etc...). Other suffixes like "-allah"/"-ullah"/"-ollah" are extremely common as well (e.g., Nasrallah). This is to say that "El Dine" and "Allah" are almost always the 2nd part of a surname (at least one more word is needed on the left to complete the surname)

    Middle names hardly exist An Arabic-looking name is a good hint that there is no middle name. Arabic cultures adopt chaining of names instead of middle names (first name, followed by father's name, followed by father's father's name, etc..., and then the surname).

    Edit: Honestly, the Wikipedia page discusses this really well https://en.wikipedia.org/wiki/Arabic_name

    enhancement 
    opened by us88 1
Releases(v1.1.2.1)
An online markdown resume template project, based on pywebio

An online markdown resume template project, based on pywebio

极简XksA 5 Nov 10, 2022
A Python package to facilitate research on building and evaluating automated scoring models.

Rater Scoring Modeling Tool Introduction Automated scoring of written and spoken test responses is a growing field in educational natural language pro

ETS 59 Oct 10, 2022
Split large XML files into smaller ones for easy upload

Split large XML files into smaller ones for easy upload. Works for WordPress Posts Import and other XML files.

Joseph Adediji 1 Jan 30, 2022
PyMultiDictionary is a Dictionary Module for Python 3+ to get meanings, translations, synonyms and antonyms of words in 20 different languages

PyMultiDictionary PyMultiDictionary is a Dictionary Module for Python 3+ to get meanings, translations, synonyms and antonyms of words in 20 different

Pablo Pizarro R. 19 Dec 26, 2022
strbind - lapidary text converter for translate an text file to the C-style string

strbind strbind - lapidary text converter for translate an text file to the C-style string. My motivation is fast adding large text chunks to the C co

Mihail Zaytsev 1 Oct 22, 2021
AnnIE - Annotation Platform, tool for open information extraction annotations using text files.

AnnIE - Annotation Platform, tool for open information extraction annotations using text files.

Niklas 29 Dec 20, 2022
Wikipedia Reader for the GNOME Desktop

Wike Wike is a Wikipedia reader for the GNOME Desktop. Provides access to all the content of this online encyclopedia in a native application, with a

Hugo Olabera 126 Dec 24, 2022
This is a text summarizing tool written in Python

Summarize Written by: Ling Li Ya This is a text summarizing tool written in Python. User Guide Some things to note: The application is accessible here

Marcus Lee 2 Feb 18, 2022
知乎评论区词云分析

zhihu-comment-wordcloud 知乎评论区词云分析 起源于:如何看待知乎问题“男生真的很不能接受彩礼吗?”的一个回答下评论数超8万条,创单个回答下评论数新记录? 项目代码说明 2.download_comment.py 下载全量评论 2.word_cloud_by_dt 生成词云 2

李国宝 10 Sep 26, 2022
Amazing GitHub Template - Sane defaults for your next project!

🚀 Useful README.md, LICENSE, CONTRIBUTING.md, CODE_OF_CONDUCT.md, SECURITY.md, GitHub Issues and Pull Requests and Actions templates to jumpstart your projects.

276 Jan 01, 2023
Returns unicode slugs

Python Slugify A Python slugify application that handles unicode. Overview Best attempt to create slugs from unicode strings while keeping it DRY. Not

Val Neekman 1.3k Jan 04, 2023
Free & simple way to encipher text

VenSipher VenSipher is a free medium through which text can be enciphered. It can convert any text into an unrecognizable secret text that can only be

3 Jan 28, 2022
A generator library for concise, unambiguous and URL-safe UUIDs.

Description shortuuid is a simple python library that generates concise, unambiguous, URL-safe UUIDs. Often, one needs to use non-sequential IDs in pl

Stavros Korokithakis 1.8k Dec 31, 2022
A production-ready pipeline for text mining and subject indexing

A production-ready pipeline for text mining and subject indexing

UF Open Source Club 12 Nov 06, 2022
A Python library that provides an easy way to identify devices like mobile phones, tablets and their capabilities by parsing (browser) user agent strings.

Python User Agents user_agents is a Python library that provides an easy way to identify/detect devices like mobile phones, tablets and their capabili

Selwin Ong 1.3k Dec 22, 2022
🍋 A Python package to process food

Pyfood is a simple Python package to process food, in different languages. Pyfood's ambition is to be the go-to library to deal with food, recipes, on

Local Seasonal 8 Apr 04, 2022
Deasciify-highlighted - A Python script for deasciifying text to Turkish and copying clipboard

deasciify-highlighted is a Python script for deasciifying text to Turkish and copying clipboard.

Ümit Altıntaş 3 Mar 18, 2022
Python library for creating PEG parsers

PyParsing -- A Python Parsing Module Introduction The pyparsing module is an alternative approach to creating and executing simple grammars, vs. the t

Pyparsing 1.7k Dec 27, 2022
The Levenshtein Python C extension module contains functions for fast computation of Levenshtein distance and string similarity

Contents Maintainer wanted Introduction Installation Documentation License History Source code Authors Maintainer wanted I am looking for a new mainta

Antti Haapala 1.2k Dec 16, 2022
一款高性能敏感词(非法词/脏字)检测过滤组件,附带繁体简体互换,支持全角半角互换,汉字转拼音,模糊搜索等功能。

一款高性能非法词(敏感词)检测组件,附带繁体简体互换,支持全角半角互换,获取拼音首字母,获取拼音字母,拼音模糊搜索等功能。

ToolGood 3.6k Jan 07, 2023