human-name
A library and command-line client for parsing and comparing human names.
Uses and limitations
If you are trying to programmatically put human names into a canonical format, you are of course in a state of sin. But sometimes, something is better than nothing.
If you want to let your users enter arbitrary names but try to use a given name in a salutation, or you're looking for a person's index in PubMed's list of authors for a co-authored paper, or you want to extract surnames from unstructured name entries for a frequency analysis, you might find this useful.
Most names are not unique. human_name
will tell you that "J. Doe" might be "Jane Doe",
but of course it might not be, and even "Jane Doe" might not be the other "Jane Doe."
The comparison logic here is only useful if you have external reason to believe
two names may represent the same person.
human_name
will work best on Latin names - i.e., data from North or South America
and/or Europe. For example, it doesn't understand surname-first formats without
commas, common in East Asia: "Park Geun-hye" will be parsed as having the given
name "Park", and the last name "Guen-hye". And it doesn't handle single-word names.
It won't blow up on Unicode, and it handles non-ASCII punctuation and accents
with some intelligence, but don't feed in Arabic or Han characters and expect
better results than a naive whitespace or word-boundary split.
human_name
tries to fail nicely, such that if parsing fails, either it will do
so explicitly, returning nothing, or at least, calling display_full
on the result
will return the input, modulo whitespace. But there are no guarantees.
human_name
tries aggressively to treat strings as names, which makes it
definitely not suitable for extracting names from a larger piece of text
(although it will strip titles, nicknames, etc, from a name field.)
Because the goals of this library include both name comparison and memory efficiency, parsed names are Unicode NFKD-normalized and capitalized in a conventional way (handling "Mc" and a few other edge cases), and the raw input is not preserved.
Supported environments
Anywhere that nightly Rust will run. (We depend on nightly Rust because we make use of Rust-PHF's syntax extensions.)
From Rust code
use Name;
let jane_doe = parse.unwrap;
let john_doe = parse.unwrap;
let j_doe = parse.unwrap;
assert!;
assert!;
let oscar = parse.unwrap;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
assert!;
See the docs for details.
From the command line
There are two modes, "parse" and "eq". The mode is passed as the first argument. You can pass input as subsequent arguments:
}
}
Or, with the second argument "-", you can pass input on stdin. For example, to find the most common surnames in a file of newline-delimited names:
| | | | |
To find all the possible "J. Smith"s in a file of newline-delimited names:
Bindings in other languages
Ruby bindings using the ffi
gem are available at github.com/djudd/human-name-rb
Python bindings using the ctypes
module are available at github.com/djudd/human-name-py
Credit
Inspiration, heuristics, and test cases were taken from:
people
(Ruby)nameparser
(Python)HumanNameParse
(Java)namae
(Ruby)Lingua::EN::NameParse
(Perl) (probably the original for some of the other ports as well)Lingua::EN::Nickname
(Perl)
In terms of name formats, human_name
covers just about all the cases these libraries
do, and more. However, at the moment, unlike most of them, it throws away titles and
nicknames, rather than merely separating them.
I wrote this mostly as a side project to learn Rust (so apologies for any unidiomatic code), but thanks also to Academia.edu for giving me real-world use cases.
Contributing
Please do! I'm not going to set up a CONTRIBUTING.md until there's evidence anyone is actually interested, but feel free either to just submit a pull request or to email me (see Cargo.toml) if you have any questions.
License
Apache 2.0 - see LICENSE.