name-variants
Multilingual name romanization lookup across Chinese, Japanese, Korean, Arabic, Vietnamese, and more. Resolves whether two name spellings refer to the same person — Chan/Chen/陳/陈, Hsu/Xu, Chou/Zhou — across Pinyin, Wade-Giles, Cantonese, Hokkien, and other romanization systems.
README
name-variants
"Chan" is simultaneously 陳, 陈 and 찬 and จัน — lookup() returns all of them.
Every romanization system produces a member of an equivalence class: no canonical form, no ordering dependency, no silent data loss. share_cluster("Hsu", "Xu") is True. lookup("Chan") returns a Chinese surname cluster and a Korean given-name cluster, sorted by bearer count.
Available as a Python library, CLI, pandas accessor, and Model Context Protocol (MCP) server.
pip install name-variants
The core idea
A NameCluster is a frozenset of co-equal representations. 陳, 陈, chen, chan, tan, chern are all members of the same Chinese surname cluster — none is more "real" than another. lookup() returns every cluster that contains your query, sorted by frequency:
from name_variants import lookup, share_cluster
clusters = lookup("Chan")
# [NameCluster(language='chinese', 8 forms),
# NameCluster(language='korean_given', 3 forms)]
# Both Chinese scripts are in the same cluster — co-equal
assert "陈" in clusters[0] # Simplified
assert "陳" in clusters[0] # Traditional
# Membership is case-insensitive
assert "CHAN" in clusters[0]
# Ambiguity is surfaced, not suppressed
assert len(clusters) == 2 # Chinese AND Korean, not one-or-the-other
API
lookup() — all matching clusters
from name_variants import lookup
lookup("Chan")
# [NameCluster(language='chinese', 8 forms),
# NameCluster(language='korean_given', 3 forms)]
lookup("Nguyen")
# [NameCluster(language='vietnamese', 4 forms)]
lookup("Smith")
# []
Results are sorted by frequency descending — most statistically likely interpretation first.
share_cluster() — equivalence check
from name_variants import share_cluster
share_cluster("Chan", "Chen") # True — same Chinese cluster
share_cluster("Chou", "Zhou") # True — Wade-Giles = Pinyin
share_cluster("Chiang", "Jiang") # True — Chiang Kai-shek / 蒋介石
share_cluster("Hsu", "Xu") # True — Taiwan diaspora romanization
share_cluster("Tsao", "Cao") # True — Ts'ao Ts'ao / 曹操
share_cluster("Chan", "Kim") # False — different names
share_cluster("", "Chan") # False — empty input
dialect() — Chinese romanization system tag
from name_variants import dialect
dialect("chen") # "mandarin_pinyin"
dialect("chan") # "cantonese"
dialect("tan") # "hokkien"
dialect("chou") # "wade_giles"
dialect("hsu") # "wade_giles"
dialect("陳") # "traditional"
dialect("Smith") # None
normalize() — text preprocessing
from name_variants import normalize
normalize(" NGUYỄN ") # "nguyễn"
normalize("Nguyễn", strip_diacritics=True) # "nguyen"
normalize("chan") # strips zero-width spaces
CLI
nv lookup Chan
# [chinese] (~90M bearers)
# 陈 陳 chan chen tan ...
# [korean_given]
# 찬 chan chahn
nv match Chan Chen # true
nv match Chan Kim # false
nv match --exit-code Chan Chen && echo same # shell-scripting friendly
nv canonicalize-csv names.csv --col name --out out.csv
# adds {name}_canonical column
nv dedupe names.csv --col name --out out.csv
# adds cluster_id column grouping romanization variants
Pandas
pip install "name-variants[pandas]"
import pandas as pd
import name_variants # registers .nv accessor
s = pd.Series(["Chan", "Chen", "Smith", "Park"])
s.nv.lookup()
# 0 [NameCluster(chinese, ...), NameCluster(korean_given, ...)]
# 1 [NameCluster(chinese, ...)]
# 2 []
# 3 [NameCluster(korean, ...)]
s.nv.cluster_id()
# 0 a3f2b1c4d5e6 ← same as row 1 (Chan and Chen share chinese cluster)
# 1 a3f2b1c4d5e6
# 2 ← empty string for unknown
# 3 9b8c7d6e5f4a
a = pd.Series(["Chan", "Park"])
b = pd.Series(["Chen", "Bak"])
a.nv.share_cluster_with(b) # [True, True]
MCP server (Model Context Protocol)
name-variants ships a built-in Model Context Protocol server, exposing name lookup as MCP tools that any MCP-compatible AI client (Claude Desktop, Claude Code, Cursor, etc.) can call directly.
Claude Code:
claude mcp add name-variants -- uvx --from "name-variants[mcp]" nv-mcp
Claude Desktop — add to claude_desktop_config.json:
{
"mcpServers": {
"name-variants": {
"command": "uvx",
"args": ["--from", "name-variants[mcp]", "nv-mcp"]
}
}
}
Three MCP tools are exposed:
| Tool | Arguments | Returns |
|---|---|---|
lookup |
text: str |
list of {language, forms[], frequency} clusters |
share_cluster |
a: str, b: str |
true / false |
dialect |
text: str |
romanization system string or null |
Language tables
| Language | Entries | Coverage |
|---|---|---|
chinese |
140 | Pinyin + Wade-Giles + Cantonese + Hokkien + Hakka + Teochew + Traditional |
japanese |
143 | Hepburn + macron variants |
korean |
100 | Revised Romanization + McCune-Reischauer |
arabic |
92 | Multiple transliteration systems |
vietnamese |
84 | Diacritics + stripped forms |
russian |
79 | Multiple transliteration systems |
indonesian_malay |
77 | — |
persian |
80 | — |
indian_hindi |
80 | — |
hebrew |
75 | — |
turkish |
74 | Dotted-İ variants |
greek |
60 | — |
thai |
68 | — |
indian_bengali |
56 | — |
indian_tamil |
53 | — |
chinese_given |
120 | Common given-name characters with Pinyin |
korean_given |
70 | Common given-name syllables |
japanese_given |
107 | Common given-name kanji |
from name_variants import ALL_TABLES
list(ALL_TABLES.keys()) # all 18 table names
Chinese romanization systems
| System | Examples |
|---|---|
| Mandarin Pinyin | Zhou, Zhang, Wang, Xu |
| Wade-Giles | Chou, Chang, Wang, Hsu, Tsao, Kuo, Hsieh |
| Cantonese (Jyutping/Yale) | Chan, Wong, Ng, Lam, Tsui |
| Hokkien/Min Nan | Tan, Ng, Lim, Goh |
| Hakka | Fong, Thong |
| Teochew | Teo, Ng |
| Postal romanization | Peking, Nanking, Chungking |
| Traditional characters | 陳, 劉, 張, 楊, 趙 |
NameCluster reference
@dataclass(frozen=True)
class NameCluster:
forms: frozenset[str] # all representations — co-equal
language: str # "chinese", "korean", "vietnamese", etc.
frequency: int | None # approximate global bearer count
def __contains__(self, text: str) -> bool # case-insensitive
def __iter__(self) # iterate all forms
def __len__(self)
Why equivalence classes instead of a canonical key?
A canonical-key model forces a false choice: "Chan" must map to either 陈 or 찬, not both. Table ordering becomes load-bearing — whichever table is consulted last wins. Romanizations must be stripped from given-name tables to prevent collisions.
The NameCluster model eliminates this: every romanization system's output is just another member of a frozenset. lookup() returns all matching clusters. Ambiguity is surfaced, not suppressed. The most likely interpretation comes first by frequency.
Contributing
git clone https://github.com/SecurityRonin/name-variants
cd name-variants
pip install -e ".[dev]"
pytest
Data files are in name_variants/*_names.py and name_variants/*_surnames.py. Each entry is a plain Python dict — easy to read and edit:
"陈": {
"forms": ["陳", "chen", "chan", "tan", ...],
"frequency": 90_000_000,
"dialects": {
"chen": "mandarin_pinyin",
"chan": "cantonese",
"tan": "hokkien",
"陳": "traditional",
},
},
Adding a new variant is one edit to one entry — forms, frequency, and dialect tag colocated.
Privacy Policy · Terms of Service · © 2026 Security Ronin Ltd
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。