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)
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 python package that lets you add custom colors and text formatting to your scripts in a very easy way!

colormate Python script text formatting package What is colormate? colormate is a python library that lets you add text formatting to your scripts, it

Rodrigo 2 Dec 14, 2022
Production First and Production Ready End-to-End Keyword Spotting Toolkit

WeKws Production First and Production Ready End-to-End Keyword Spotting Toolkit. The goal of this toolkit it to... Small footprint keyword spotting (K

222 Dec 30, 2022
This repository contains scripts to control a RGB text fan attached to a Raspberry Pi.

RGB Text Fan Controller This repository contains scripts to control a RGB text fan attached to a Raspberry Pi. Setup The Raspberry Pi and RGB text fan

Luke Prior 1 Oct 01, 2021
Etranslate is a free and unlimited python library for transiting your texts

Etranslate is a free and unlimited python library for transiting your texts

Abolfazl Khalili 16 Sep 13, 2022
Convert ebooks with few clicks on Telegram!

E-Book Converter Bot A bot that converts e-books to various formats, powered by calibre! It currently supports 34 input formats and 19 output formats.

Youssif Shaaban Alsager 45 Jan 05, 2023
A minimal code sceleton for a textadveture parser written in python.

Textadventure sceleton written in python Use with a map file generated on https://www.trizbort.io Use the following Sockets for walking directions: n

1 Jan 06, 2022
A query extract python package

A query extract python package

Fayas Noushad 4 Nov 28, 2021
Extract price amount and currency symbol from a raw text string

price-parser is a small library for extracting price and currency from raw text strings.

Scrapinghub 252 Dec 31, 2022
Vector space based Information Retrieval System for Text Processing - Information retrieval

Information Retrieval: Text Processing Group 13 Sequence of operations Install Requirements Add given wikipedia files to the corpus directory. Downloa

1 Jan 01, 2022
Migrates translations to the REDCap native Multi-Language Management system

Automates much of the process of moving translations from the old Multilingual external module to the newer built-in Multi-Language Management (MLM) page.

UCI MIND 3 Sep 27, 2022
Umamusume story patcher with python

umamusume-story-patcher How to use Go to your umamusume folder, usually C:\Users\user\AppData\LocalLow\Cygames\umamusume Make a mods folder and clon

8 May 07, 2022
Repository containing the code for An-Gocair text normaliser

Scottish Gaelic Text Normaliser The following project contains the code and resources for the Scottish Gaelic text normalisation project. The repo can

3 Jun 28, 2022
Aml - anti-money laundering

Anti-money laundering Dedect relationship between A and E by tracing through payments with similar amounts and identifying payment chains. For example

3 Nov 21, 2022
知乎评论区词云分析

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

李国宝 10 Sep 26, 2022
A simple Python module for parsing human names into their individual components

Name Parser 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.suff

Derek Gulbranson 574 Dec 20, 2022
Little python script + dictionary to help solve Wordle puzzles

Wordle Solver Little python script + dictionary to help solve Wordle puzzles Usage Usage: ./wordlesolver.py [letters in word] [letters not in word] [p

Luke Stephens (hakluke) 4 Jul 24, 2022
WorldCloud Orçamento de Estado 2022

World Cloud Orçamento de Estado 2022 What it does This script creates a worldcloud, masked on a image, from a txt file How to run it? Install all libr

Jorge Gomes 2 Oct 12, 2021
An extension to detect if the articles content match its title.

Clickbait Detector An extension to detect if the articles content match its title. This was developed in a period of 24-hours in a hackathon called 'H

Arvind Krishna 5 Jul 26, 2022
Maiden & Spell community player ranking based on tournament data.

MnSRank Maiden & Spell community player ranking based on tournament data. Why? 2021 just ended and this seemed like a cool idea. Elo doesn't work well

Jonathan Lee 1 Apr 20, 2022