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)
Adventura is an open source Python Text Adventure Engine

Adventura Adventura is an open source Python Text Adventure Engine, Not yet uplo

5 Oct 02, 2022
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
Repositori untuk belajar pemrograman Python dalam bahasa Indonesia

Python Repositori ini berisi kumpulan dari berbagai macam contoh struktur data, algoritma dan komputasi matematika yang diimplementasikan dengan mengg

Bellshade 111 Dec 19, 2022
Phone Number formatting for PlaySMS Platform - BulkSMS Platform

BulkSMS-Number-Formatting Phone Number formatting for PlaySMS Platform - BulkSMS Platform. Phone Number Formatting for PlaySMS Phonebook Service This

Edwin Senunyeme 1 Nov 08, 2021
Hspell, the free Hebrew spellchecker and morphology engine.

Hspell, the free Hebrew spellchecker and morphology engine.

16 Sep 15, 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
Make writing easier!

Handwriter Make writing easier! How to Download and install a handwriting font, or create a font from your handwriting. Use a word processor like Micr

64 Dec 25, 2022
一个可以可以统计群组用户发言,并且能将聊天内容生成词云的机器人

当前版本 v2.2 更新维护日志 更新维护日志 有问题请加群组反馈 Telegram 交流反馈群组 点击加入 演示 配置要求 内存:1G以上 安装方法 使用 Docker 安装 Docker官方安装

机器人总动员 117 Dec 29, 2022
A collection of pre-commit hooks for handling text files.

texthooks A collection of pre-commit hooks for handling text files. In particular, hooks for handling unicode characters which may be undesirable in a

Stephen Rosen 5 Oct 28, 2022
Word and phrase lists in CSV

Word Lists Word and phrase lists in CSV, collected from different sources. Oxford Word Lists: oxford-5k.csv - Oxford 3000 and 5000 oxford-opal.csv - O

Anton Zhiyanov 14 Oct 14, 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
Redlines produces a Markdown text showing the differences between two strings/text

Redlines Redlines produces a Markdown text showing the differences between two strings/text. The changes are represented with strike-throughs and unde

Houfu Ang 2 Apr 08, 2022
The bot creates hashtags for user's texts in Russian and English.

telegram_bot_hashtags The bot creates hashtags for user's texts in Russian and English. It is a simple bot for creating hashtags. NOTE file config.py

Yana Davydovich 2 Feb 12, 2022
Converts a Bangla numeric string to literal words.

Bangla Number in Words Converts a Bangla numeric string to literal words. Install $ pip install banglanum2words Usage

Syed Mostofa Monsur 3 Aug 29, 2022
Python Lex-Yacc

PLY (Python Lex-Yacc) Copyright (C) 2001-2020 David M. Beazley (Dabeaz LLC) All rights reserved. Redistribution and use in source and binary forms, wi

David Beazley 2.4k Dec 31, 2022
Vastasanuli - Vastasanuli pelaa Sanuli-peliä.

Vastasanuli Vastasanuli pelaa SANULI -peliä. Se ei aina voita. Käyttö Tarttet Pythonin (3.6+). Aja make (tai lataa words.txt muualta) Asentele vaaditt

Aarni Koskela 1 Jan 06, 2022
🐸 Identify anything. pyWhat easily lets you identify emails, IP addresses, and more. Feed it a .pcap file or some text and it'll tell you what it is! 🧙‍♀️

🐸 Identify anything. pyWhat easily lets you identify emails, IP addresses, and more. Feed it a .pcap file or some text and it'll tell you what it is! 🧙‍♀️

Brandon 5.6k Jan 03, 2023
Text to ASCII and ASCII to text

Text2ASCII Description This python script (converter.py) contains two functions: encode() is used to return a list of Integer, one item per character

4 Jan 22, 2022
Python port of Google's libphonenumber

phonenumbers Python Library This is a Python port of Google's libphonenumber library It supports Python 2.5-2.7 and Python 3.x (in the same codebase,

David Drysdale 3.1k Dec 29, 2022