33 个版本 (21 个稳定版本)
2.0.3 | 2024 年 3 月 23 日 |
---|---|
2.0.2 | 2023 年 5 月 7 日 |
2.0.1 | 2022 年 9 月 30 日 |
1.4.1 | 2022 年 7 月 30 日 |
0.6.2 | 2016 年 2 月 27 日 |
#79 在 解析器实现
99,055 每月下载量
在 texlab 中使用
180KB
4K SLoC
human-name
一个用于解析和比较人名的库和命令行客户端。
用途和限制
如果您试图以编程方式将人名放入规范格式,当然您处于 一种罪恶状态。但有时,有点比没有好。
如果您想允许用户输入任意名称,但尝试在问候语中使用给定名称,或者您正在寻找PubMed作者列表中合作论文的作者的索引,或者您想从非结构化的人名条目中提取姓氏进行频率分析,您可能会觉得这个库很有用。
大多数姓名都不是唯一的。《code>human_name 会告诉您 "J. Doe" 可能是 "Jane Doe",但当然也可能不是,甚至 "Jane Doe" 也可能不是另一个 "Jane Doe"。这里的比较逻辑只有在您有外部理由相信两个姓名可能代表同一个人时才有用。
human_name
在拉丁姓名上表现最佳 - 即来自北美洲和/或欧洲的数据。例如,它不理解东亚常见的逗号分隔的姓氏优先格式:"Park Geun-hye" 会被解析为给定名为 "Park",姓氏为 "Guen-hye"。它也不处理单词姓名。它不会在 Unicode 上崩溃,并且能够智能地处理非 ASCII 标点符号和重音符号,但不要输入阿拉伯语或汉字字符并期望比简单的空白或单词边界分割更好的结果。
human_name
尝试优雅地失败,如果解析失败,它将明确失败,返回空值,或者至少,在结果上调用 display_full
将返回输入,除了空格。
human_name
尝试积极地将字符串视为姓名,这使得它肯定不适用于从更大的文本中提取姓名(尽管它可以从姓名字段中去除头衔、昵称等。)
因为这个库的目标包括名称比较和内存效率,解析后的名称使用Unicode NFKD规范化并以传统方式首字母大写(处理“Mc”和其他一些边缘情况),并且不保留原始输入。
来自Rust代码
use human_name::Name;
let jane_doe = Name::parse("Jane Doe").unwrap();
let john_doe = Name::parse("John Doe").unwrap();
let j_doe = Name::parse("Doe, J.").unwrap();
assert!(jane_doe.consistent_with(&j_doe));
assert!(!jane_doe.consistent_with(&john_doe));
let oscar = Name::parse("MR OSCAR DE LA HOYA JR").unwrap();
assert_eq!(Some("Oscar"), oscar.given_name());
assert_eq!("de la Hoya", oscar.surname());
assert_eq!(Some("Jr."), oscar.generational_suffix());
assert_eq!(Some("Mr."), oscar.honorific_prefix());
assert_eq!("Oscar de la Hoya, Jr.", oscar.display_full());
assert!(Name::parse("[email protected]").is_none());
有关详细信息,请参阅文档。
来自命令行
有两种模式:“解析”和“eq”。模式作为第一个参数传递。您可以将输入作为后续参数传递
$ human_name parse "Jane Doe"
{"first_initial":"J","given_name":"Jane","surname":"Doe"}
$ human_name parse "MR OSCAR DE LA HOYA JR"
{"first_initial":"O","given_name":"Oscar","generational_suffix":"Jr.","surname":"de la Hoya"}
$ human_name eq "Jane Doe" "Jane M. Doe"
y
$ echo $?
0
$ human_name eq "Jane M. Doe" "Jane H. Doe"
n
$ echo $?
1
或者,使用第二个参数“-”,您可以将输入传递到stdin。例如,要在一个以换行符分隔的名称文件中找到最常见的姓氏
$ human_name parse - < names.txt | jq .surname | sort | uniq -c | sort -nr | head -n3
111 "Zhang"
109 "Li"
106 "Wang"
要在一个以换行符分隔的名称文件中找到所有可能的“J. Smith”
$ human_name eq - "J Smith" < names.text
Smith, Jason A.
Jay Smith
可选功能
以下功能是可选的,默认关闭
name_eq_hash
为Name
实现Eq
使用consistent_with
,以及使用surname_hash
实现Hash
。
这是可选的,因为这两个实现都存在疑问,不适合通用用途:这个Eq
不是传递的,而Hash
则容易发生冲突。有关详细信息,请参阅文档。
序列化
使用serde
为Name
实现序列化。这种序列化格式旨在允许不使用human_name
的程序查看解析结果;未实现反序列化,因为当需要往返时,只需使用display_full
将字符串序列化,然后使用parse
进行反序列化应产生更紧凑且性能合理的输出。
其他语言的绑定
使用ffi
宝石的Ruby绑定可在github.com/djudd/human-name-rb找到
使用ctypes
模块的Python绑定可在github.com/djudd/human-name-py找到
Elixir绑定(第三方)可在https://github.com/amokan/human_name找到
版本控制
关于其程序性API,这个库遵循semver
。对解析和一致性检查启发式算法的更改不被视为破坏性的,并且通常会伴随着小版本号的提升。
性能
截至2.0版本,名称解析的快速路径(大致上,两个空格分隔的大写ASCII单词)在我的M1 Macbook上需要~200ns,并且不分配堆内存。如果姓氏哈希匹配,则比较两个简单名称的一致性需要~100ns,否则需要~1ns。两种情况中的任何一种的异常情况可能需要更长的时间。
贡献
欢迎贡献、功能请求和错误报告。请打开GitHub问题或拉取请求,并尽可能提供有帮助的上下文,我们将从那里着手。由于这是一个小型个人项目,您可能不会立即收到回复,但我会尽快跟进。
与该项目相关的对话必须遵守贡献者公约的行为准则。请将任何相关问题报告给Cargo.toml中的联系电子邮件。
致谢
灵感、启发式方法和测试用例来自
people
(Ruby)nameparser
(Python)HumanNameParse
(Java)namae
(Ruby)Lingua::EN::NameParse
(Perl)(可能是其他一些端口的原版)Lingua::EN::Nickname
(Perl)parse-full-name
(JS)PHP-Name-Parser
(PHP)
许可证
Apache 2.0 - 查看 LICENSE 文件。
依赖项
约 5.5MB
约 165K SLoC