From d660bd024ce07d99d0d0f405b95c503794d4d44d Mon Sep 17 00:00:00 2001 From: Derek Gulbranson Date: Sat, 17 Oct 2026 14:26:46 -0700 Subject: [PATCH 1/4] Add Chinese and Japanese credential and office words as suffixes (#671) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds 議員, 国会議員, 太平紳士, 医学博士, 二世 and the job titles 社長/部長/課長 (with variant spellings) to SUFFIX_WORDS, so they read as suffixes when spaced or after a comma instead of reversing the name or joining the given name. None joins GLUED_HONORIFICS: the glued bar was not measured against real names, and 部長 fails it outright (阿部長). Amends rules.md S2/W2, adds the decisions.md entry, release-log bullet, case rows, and re-records the snapshot and agreement records. Co-Authored-By: Claude Sonnet 5.5 --- docs/design/decisions.md | 1 + docs/design/rules.md | 15 ++++++ docs/release_log.rst | 1 + nameparser/config/suffixes.py | 24 ++++++++++ tests/v2/cases.py | 47 +++++++++++++++++++ tools/differential/cldr_agreement.json | 24 +++++----- .../differential/cldr_agreement_locales.json | 24 +++++----- tools/differential/corpus_cjk.jsonl | 8 ++++ tools/differential/corpus_rules.jsonl | 6 +++ tools/differential/snapshot.jsonl | 17 +++++-- 10 files changed, 139 insertions(+), 28 deletions(-) diff --git a/docs/design/decisions.md b/docs/design/decisions.md index 73027fed..428163e8 100644 --- a/docs/design/decisions.md +++ b/docs/design/decisions.md @@ -644,6 +644,7 @@ Declined: - 2026-08 #308 — an entry peels only where it can never end a name: 씨/님/さん/様/先生 peel; 양/군/氏/博士/殿 stay spaced-only; 君 is in neither set while its kana spelling くん peels. The vocabulary carries the license, so no structural or per-script gate stands over the peel. - 2026-08 #312 — the peel crosses the family comma and the 间隔号: both answer where a name DIVIDES into surname and given, a question the peel never asks. Provenance matters here: neither gate was argued for the peel specifically — both came with the placement (#312's own framing) — so the crossing was a repair of inherited gates, not a designed-in property. - 2026-08 #319 — a wholly suffix-shaped second run is declined as a peel site (the "田中さん, V." shape), but only when the name's own run offers a site, since a glued honorific is itself part of what makes a run read as suffix-shaped. +- 2026-10-17 #671 — SPACED AND AFTER-COMMA ONLY, no glued peel (Derek, 2026-10-17). 議員/议员, 国会議員/國會議員, 太平紳士/太平绅士, 医学博士/醫學博士, 二世 and the job titles 社長/部長/課長 join `SUFFIX_WORDS`; none joins `GLUED_HONORIFICS`. The spaced bar is only that a word standing alone is no name, so they ship; the glued bar ("can it END a name?") needs real-name counts that this change did not get — the Wikidata suffix query timed out and the 910-name native corpus holds none of the words — and 部長 fails it on argument alone (長 is a borne given name, 阿部長). A follow-up can vet 医学博士, 議員 and 太平紳士 one at a time. Consequence measured on `parser_for(locales.ZH)`: `王二世` reads family 王, suffix 二世 (it read given 二世), because the segmenter's division is not a peel and the split-off 二世 is then a whole-token suffix word, the way 王博士 already reads; `陳怡君二世` still reads given 怡君二世 (glued, nothing divides it). ジュニア was already shipped by #661. Excluded as the issue stated: 小 (a prefix and a common given-name character) and 冯/馮 for "von" (a top-30 surname). Excluded (the never-given / ambiguous particle line, nameparser/config/particles.py — #360 owns the vocabulary question): diff --git a/docs/design/rules.md b/docs/design/rules.md index 02f972e4..973bafcf 100644 --- a/docs/design/rules.md +++ b/docs/design/rules.md @@ -1244,6 +1244,9 @@ S2. Rationale: generational suffixes and credentials are recognized "Агриппина Младшая" → suffix="Младшая" "جورج بوش الابن" → suffix="الابن" "ロバート・ダウニー・ジュニア" → suffix="ジュニア" + "佐藤恵子 国会議員" → suffix="国会議員" + "王雅婷,議員" → suffix="議員" + "陳子媚 二世" → suffix="二世" "Питер Брейгель мл." → suffix="мл." "Marie Fils" → family="Fils" · boundary "Jiří Dienstbier ml." → family="ml." · boundary @@ -2362,6 +2365,18 @@ W2. Rationale: some East Asian honorifics glue directly onto the end "김지양" → suffix="" · boundary "선생님" → family="선생님" · boundary "王君" → family="王君" · boundary + "田中 社長" → suffix="社長" + "田中部長" → family="田中部長" · boundary + "陳怡君二世" → family="陳怡君二世" · boundary + Accepted: the credential, office and generational words of #671 + (議員, 国会議員, 太平紳士, 医学博士, 二世, 社長, 部長, 課長 and their + variant spellings) are vocabulary in the spaced and after-comma + positions only and are NOT peeled when glued: 陳怡君二世 and + 田中部長 keep the word in the name. The glued bar is "can it END + a name?", and none of these was measured against real names + (部長 fails it outright, 阿部長 being 阿部 + 長). The Han + segmenter's own division is not a peel and can still expose one: + 王二世 under the Chinese pack reads family 王, suffix 二世. history: decisions.md#W2 · interacts: W3 · implemented: nameparser/_pipeline/_script_segment.py W3. Rationale: a family name declared by a comma is the writer's diff --git a/docs/release_log.rst b/docs/release_log.rst index 98f2344e..195341ca 100644 --- a/docs/release_log.rst +++ b/docs/release_log.rst @@ -8,6 +8,7 @@ Release Log - **Add junior and senior in other languages as suffixes.** ``Antonio Pavlović mlađi`` gives last ``Pavlović``, suffix ``mlađi``, where 1.4.0 through 2.4.2 gave middle ``Pavlović``, last ``mlađi``. The words come from 45 languages and are read when written as a separate word after the name. :issue:`661`, :issue:`679` - **Remove mai from the default post-nominal acronyms, so a trailing Mai keeps the name.** ``Tran Thi Mai`` read in Vietnamese order (``FAMILY_FIRST_GIVEN_LAST``) gives given ``Mai``, middle ``Thi``, family ``Tran``, where 2.0.0 through 2.4.2 gave suffix ``Mai`` and no given name; ``Nguyen Mai`` gives family ``Mai``, as 1.4.0 did. The cost is that ``John Smith MAI`` gives last ``MAI`` instead of suffix; ``Smith, John, MAI`` and ``John Smith M.A.I.`` still read as credentials. A caller who needs it back adds it: ``Lexicon.default().add(suffix_acronyms={"mai"})``. See the ``suffix-acronym-collisions`` entry of ``docs/design/decisions.md`` (:issue:`687`) + - **Add Chinese and Japanese credential, office and generational words as suffixes.** ``彭德威 议员`` under ``locales.ZH`` gives family ``彭``, given ``德威``, suffix ``议员``, where 2.0 through 2.4.2 gave middle ``议员``; ``王雅婷,議員`` gives suffix ``議員``, where it gave given ``議員`` and reversed the name. Read when written as a separate word or after a comma, not glued to the name (``陳怡君二世`` is unchanged). :issue:`671` - **Add the Akan and Indonesian salutations owura and bapak as titles.** ``Bapak Dwi Putro`` gives title ``Bapak``, first ``Dwi``, last ``Putro``, where 1.4.0 through 2.4.2 gave first ``Bapak``, middle ``Dwi``. :issue:`662` * 2.4.2 - October 13, 2026 diff --git a/nameparser/config/suffixes.py b/nameparser/config/suffixes.py index a5d5c843..9950218e 100644 --- a/nameparser/config/suffixes.py +++ b/nameparser/config/suffixes.py @@ -165,6 +165,30 @@ 'さま', # ja the kana spelling of 様 'くん', # ja the kana spelling of 君 'ちゃん', # ja familiar/diminutive + # #671: CJK credential, office and generational words. SPACED + # (and after-comma) ONLY -- none is in GLUED_HONORIFICS below. + # The spaced position is a token boundary the writer drew, so + # the vetting bar is just "is a word standing alone ever a + # name?"; the glued bar ("can it END a name?") needs real-name + # data this set was not measured against (a Wikidata suffix query + # timed out; the native-script corpus holds none of these words), + # so the glued forms (陳怡君二世, 田中社長) stay unpeeled and + # glued peeling is a separate question. + # - 二世: Japanese/Chinese "II" (the generational numeral). + # 王二世 is read family 王 + given 二世 by the Han segmenter + # today, so the glued form is exactly the open question. + # - 議員/议员, 国会議員/國會議員: legislator, Diet member. + # - 太平紳士/太平绅士: Justice of the Peace (Hong Kong). + # - 医学博士/醫學博士: Doctor of Medicine. + # - 社長/部長/課長: Japanese job titles used as forms of address + # after a name (田中 社長), not credentials -- the same slot as + # 先生. 部長 is the reason glued is out: 長 alone is a borne + # given name (阿部長 = 阿部 + 長). + '二世', + '議員', '议员', '国会議員', '國會議員', + '太平紳士', '太平绅士', + '医学博士', '醫學博士', + '社長', '部長', '課長', # #346/#344/#343: spaced trailing honorifics, South Asian and # Tibetan. SPACED ONLY -- none of these is in GLUED_HONORIFICS # below, and none may be added to it. जी is the reason and the diff --git a/tests/v2/cases.py b/tests/v2/cases.py index f2312084..4432b33e 100644 --- a/tests/v2/cases.py +++ b/tests/v2/cases.py @@ -11475,6 +11475,53 @@ def _check_cjk_shape_purity(self) -> None: "Hiroshi, an attested given name, so 博士 never peels " "-- it stays recognized in the SPACED position only, " "where the writer's own token boundary settles it"), + Case("zh_spaced_legislator_is_a_suffix", "彭德威 议员", + {"family": "彭", "given": "德威", "suffix": "议员"}, + locale="zh", classification="fix(#671)", + notes="2.4.2 read middle '议员'; the spaced word is a token " + "the writer drew, so it needs only to be no name"), + Case("ja_spaced_diet_member_is_a_suffix", "佐藤恵子 国会議員", + {"family": "佐藤恵子", "suffix": "国会議員"}, + classification="fix(#671)", + notes="2.4.2 read given '国会議員', and the unspaced twin " + "moves the same way, so the kana-licensed family-first " + "reading is unchanged"), + Case("zh_comma_legislator_is_a_suffix", "王雅婷,議員", + {"family": "王雅婷", "suffix": "議員"}, + classification="fix(#671)", tolerated=True, + notes="the fullwidth comma is a listing convention (W3, " + "best-effort); the word is vocabulary, so C1 reads the " + "part after the comma as a credential run rather than " + "reversing the name -- 2.4.2 gave it as the given name"), + Case("zh_comma_degree_is_a_suffix", "陳怡君,醫學博士", + {"family": "陳怡君", "suffix": "醫學博士"}, + classification="fix(#671)", tolerated=True, + notes="the degree the glued 博士 exclusion cannot reach: the " + "four-character word is whole after the comma"), + Case("zh_spaced_generational_two_is_a_suffix", "陳怡君 二世", + {"family": "陳", "given": "怡君", "suffix": "二世"}, + locale="zh", classification="fix(#671)", + notes="2.4.2 read middle '二世'"), + Case("ja_spaced_job_title_is_a_suffix", "田中 社長", + {"family": "田中", "suffix": "社長"}, + classification="fix(#671)", + notes="a form of address after the name, the slot 先生 " + "fills; a job title, not a credential"), + Case("ja_glued_job_title_stays", "田中部長", + {"family": "田中部長"}, + classification="fix(#271)", + notes="the glued bar is unmet: 長 alone is a borne given " + "name (阿部長 = 阿部 + 長), so 部長 is spaced-only. " + "Unchanged from 2.4.2, pinned so GLUED_HONORIFICS " + "cannot gain it unseen"), + Case("zh_glued_generational_two_is_not_peeled", "陳怡君二世", + {"family": "陳", "given": "怡君二世"}, + locale="zh", classification="fix(#271)", + notes="the glued form #671 left open: no peel reads it, " + "and 二世 is not vetted against real names. The " + "SEGMENTER's division of 王二世 is another matter -- " + "the pack reads family 王, suffix 二世, because the " + "split-off piece is a whole-token suffix word"), Case("zh_glued_jun_stays", "王君", {"family": "王君"}, classification="fix(#271)", diff --git a/tools/differential/cldr_agreement.json b/tools/differential/cldr_agreement.json index b88680d7..c2c926ea 100644 --- a/tools/differential/cldr_agreement.json +++ b/tools/differential/cldr_agreement.json @@ -13086,11 +13086,11 @@ }, "given_names": { "expected": "子媚 惠儀", - "got": "太平紳士" + "got": "" }, "suffix": { "expected": "小 太平紳士", - "got": "" + "got": "太平紳士" }, "text": "先生子媚惠儀陳小,太平紳士", "title": { @@ -13344,11 +13344,11 @@ }, "given_names": { "expected": "子媚 惠仪", - "got": "太平绅士" + "got": "" }, "suffix": { "expected": "小 太平绅士", - "got": "" + "got": "太平绅士" }, "text": "先生子媚惠仪陈小,太平绅士", "title": { @@ -13758,11 +13758,11 @@ "zh_Hant/foreignFull/givenFirst": { "family": { "expected": "馮 陳", - "got": "怡君達印馮 陳二世博士" + "got": "陳二世博士" }, "family_base": { "expected": "陳", - "got": "怡君達印馮 陳二世博士" + "got": "陳二世博士" }, "family_particles": { "expected": "馮", @@ -13770,11 +13770,11 @@ }, "given_names": { "expected": "怡君 達印", - "got": "醫學博士" + "got": "怡君達印馮" }, "suffix": { "expected": "二世 醫學博士", - "got": "" + "got": "醫學博士" }, "text": "怡君達印馮·陳二世博士,醫學博士", "title": { @@ -13886,19 +13886,19 @@ "zh_Hant/nativeFull/givenFirst": { "family": { "expected": "王", - "got": "雅婷婷婷王二世先生" + "got": "雅婷婷婷王二世" }, "family_base": { "expected": "王", - "got": "雅婷婷婷王二世先生" + "got": "雅婷婷婷王二世" }, "given_names": { "expected": "雅婷 婷婷", - "got": "議員" + "got": "" }, "suffix": { "expected": "二世 議員", - "got": "" + "got": "先生, 議員" }, "text": "雅婷婷婷王二世先生,議員", "title": { diff --git a/tools/differential/cldr_agreement_locales.json b/tools/differential/cldr_agreement_locales.json index 34e657f1..6a1987e9 100644 --- a/tools/differential/cldr_agreement_locales.json +++ b/tools/differential/cldr_agreement_locales.json @@ -617,11 +617,11 @@ }, "given_names": { "expected": "子媚 惠儀", - "got": "太平紳士" + "got": "" }, "suffix": { "expected": "小 太平紳士", - "got": "" + "got": "太平紳士" }, "text": "先生子媚惠儀陳小,太平紳士", "title": { @@ -816,11 +816,11 @@ }, "given_names": { "expected": "子媚 惠仪", - "got": "太平绅士" + "got": "" }, "suffix": { "expected": "小 太平绅士", - "got": "" + "got": "太平绅士" }, "text": "先生子媚惠仪陈小,太平绅士", "title": { @@ -1112,11 +1112,11 @@ "zh_Hant/foreignFull/givenFirst": { "family": { "expected": "馮 陳", - "got": "怡君達印馮 陳二世博士" + "got": "陳二世博士" }, "family_base": { "expected": "陳", - "got": "怡君達印馮 陳二世博士" + "got": "陳二世博士" }, "family_particles": { "expected": "馮", @@ -1124,11 +1124,11 @@ }, "given_names": { "expected": "怡君 達印", - "got": "醫學博士" + "got": "怡君達印馮" }, "suffix": { "expected": "二世 醫學博士", - "got": "" + "got": "醫學博士" }, "text": "怡君達印馮·陳二世博士,醫學博士", "title": { @@ -1240,19 +1240,19 @@ "zh_Hant/nativeFull/givenFirst": { "family": { "expected": "王", - "got": "雅婷婷婷王二世先生" + "got": "雅婷婷婷王二世" }, "family_base": { "expected": "王", - "got": "雅婷婷婷王二世先生" + "got": "雅婷婷婷王二世" }, "given_names": { "expected": "雅婷 婷婷", - "got": "議員" + "got": "" }, "suffix": { "expected": "二世 議員", - "got": "" + "got": "先生, 議員" }, "text": "雅婷婷婷王二世先生,議員", "title": { diff --git a/tools/differential/corpus_cjk.jsonl b/tools/differential/corpus_cjk.jsonl index b5c8a744..7df839b5 100644 --- a/tools/differential/corpus_cjk.jsonl +++ b/tools/differential/corpus_cjk.jsonl @@ -31,6 +31,7 @@ "ロバート・ダウニー・ジュニア" "佐々木 太郎" "佐藤 花子 \"旧姓・田中\" (旧姓 鈴木)" +"佐藤恵子 国会議員" "司马相如" "夏侯惇" "威廉·莎士比亚" @@ -52,6 +53,7 @@ "山田「タロー」太郎" "山田タロウ" "张伟" +"彭德威 议员" "毛 泽东" "毛 泽东 Dr." "毛 김" @@ -65,11 +67,13 @@ "王小明 先生" "王小明先生" "王氏" +"王雅婷,議員" "田中 さん" "田中 太郎 旧姓 佐藤 MA" "田中 太郎 様" "田中 太郎, MA" "田中 殿" +"田中 社長" "田中, 太郎 MA" "田中, 太郎さん" "田中." @@ -88,8 +92,12 @@ "田中さん." "田中さん., V." "田中博士" +"田中部長" "諸葛亮" "阿明" +"陳怡君 二世" +"陳怡君二世" +"陳怡君,醫學博士" "马丁·路德·金" "高橋 みなみ" "高橋みなみ" diff --git a/tools/differential/corpus_rules.jsonl b/tools/differential/corpus_rules.jsonl index a6150dd2..e6e175bf 100644 --- a/tools/differential/corpus_rules.jsonl +++ b/tools/differential/corpus_rules.jsonl @@ -538,6 +538,7 @@ "マイケル ジャクソン" "マイケル・ジャクソン" "ロバート・ダウニー・ジュニア" +"佐藤恵子 国会議員" "威廉·莎士比亚" "威廉・莎士比亚" "安东尼·陈志明" @@ -547,12 +548,17 @@ "毛·泽东" "毛泽东" "王君" +"王雅婷,議員" +"田中 社長" "田中. 太郎" "田中、太郎" "田中さん" "田中さん 様." "田中さん, Dr." "田中さん, PhD" +"田中部長" +"陳子媚 二世" +"陳怡君二世" "马丁·路德·金씨" "高橋 みなみ" "高橋・一郎" diff --git a/tools/differential/snapshot.jsonl b/tools/differential/snapshot.jsonl index 3da32f91..684a3bf9 100644 --- a/tools/differential/snapshot.jsonl +++ b/tools/differential/snapshot.jsonl @@ -5377,11 +5377,12 @@ {"name": "佐藤 花子 \"旧姓・田中\" (旧姓 鈴木)", "given": "花子", "family": "佐藤", "nickname": "旧姓 田中", "maiden": "鈴木", "initials": "花. 佐."} {"name": "佐藤グレース恵子", "order": "FAMILY_FIRST", "family": "佐藤グレース恵子", "initials": "佐."} {"name": "佐藤グレース恵子さん", "order": "FAMILY_FIRST", "family": "佐藤グレース恵子", "suffix": "さん", "initials": "佐."} +{"name": "佐藤恵子 国会議員", "family": "佐藤恵子", "suffix": "国会議員", "initials": "佐."} {"name": "何炅", "family": "何炅", "initials": "何."} {"name": "何瑞麟", "family": "何瑞麟", "initials": "何."} {"name": "俊年杰思陈", "family": "俊年杰思陈", "initials": "俊."} -{"name": "先生子媚惠仪陈小,太平绅士", "given": "太平绅士", "family": "先生子媚惠仪陈小", "initials": "太. 先."} -{"name": "先生子媚惠儀陳小,太平紳士", "given": "太平紳士", "family": "先生子媚惠儀陳小", "initials": "太. 先."} +{"name": "先生子媚惠仪陈小,太平绅士", "family": "先生子媚惠仪陈小", "suffix": "太平绅士", "initials": "先."} +{"name": "先生子媚惠儀陳小,太平紳士", "family": "先生子媚惠儀陳小", "suffix": "太平紳士", "initials": "先."} {"name": "克特·米勒", "given": "克特", "family": "米勒", "initials": "克. 米."} {"name": "内田誠", "family": "内田誠", "initials": "内."} {"name": "内藤博文", "family": "内藤博文", "initials": "内."} @@ -5470,8 +5471,9 @@ {"name": "張雅婷", "order": "FAMILY_FIRST", "family": "張雅婷", "initials": "張."} {"name": "張韶涵", "family": "張韶涵", "initials": "張."} {"name": "彭孟緝", "family": "彭孟緝", "initials": "彭."} +{"name": "彭德威 议员", "family": "彭德威", "suffix": "议员", "initials": "彭."} {"name": "彭德威东升", "order": "FAMILY_FIRST", "family": "彭德威东升", "initials": "彭."} -{"name": "怡君達印馮·陳二世博士,醫學博士", "given": "醫學博士", "family": "怡君達印馮 陳二世博士", "initials": "醫. 怡. 陳."} +{"name": "怡君達印馮·陳二世博士,醫學博士", "given": "怡君達印馮", "family": "陳二世博士", "suffix": "醫學博士", "initials": "怡. 陳."} {"name": "恵子グレース佐藤ジュニアさん", "family": "恵子グレース佐藤ジュニア", "suffix": "さん", "initials": "恵."} {"name": "慎太郎", "family": "慎太郎", "initials": "慎."} {"name": "慎太郎", "order": "FAMILY_FIRST", "family": "慎太郎", "initials": "慎."} @@ -5541,12 +5543,14 @@ {"name": "王镇", "family": "王镇", "initials": "王."} {"name": "王雅婷婷婷", "order": "FAMILY_FIRST", "family": "王雅婷婷婷", "initials": "王."} {"name": "王雅婷婷婷二世議員", "order": "FAMILY_FIRST", "family": "王雅婷婷婷二世議員", "initials": "王."} +{"name": "王雅婷,議員", "family": "王雅婷", "suffix": "議員", "initials": "王."} {"name": "王雪莹", "family": "王雪莹", "initials": "王."} {"name": "田中 さん", "family": "田中", "suffix": "さん", "initials": "田."} {"name": "田中 太郎 旧姓 佐藤 MA", "given": "太郎", "family": "田中", "suffix": "MA", "maiden": "佐藤", "ambiguities": ["SUFFIX_OR_NAME"], "initials": "太. 田."} {"name": "田中 太郎 様", "given": "太郎", "family": "田中", "suffix": "様", "initials": "太. 田."} {"name": "田中 太郎, MA", "given": "太郎", "family": "田中", "suffix": "MA", "ambiguities": ["SUFFIX_OR_NAME"], "initials": "太. 田."} {"name": "田中 殿", "family": "田中", "suffix": "殿", "initials": "田."} +{"name": "田中 社長", "family": "田中", "suffix": "社長", "initials": "田."} {"name": "田中, 太郎 MA", "given": "太郎", "family": "田中", "suffix": "MA", "ambiguities": ["SUFFIX_OR_NAME"], "initials": "太. 田."} {"name": "田中, 太郎さん", "given": "太郎", "family": "田中", "suffix": "さん", "initials": "太. 田."} {"name": "田中.", "family": "田中.", "initials": "田."} @@ -5566,6 +5570,7 @@ {"name": "田中さん.", "family": "田中", "suffix": "さん.", "initials": "田."} {"name": "田中さん., V.", "given": "V.", "family": "田中", "suffix": "さん.", "initials": "V. 田."} {"name": "田中博士", "family": "田中博士", "initials": "田."} +{"name": "田中部長", "family": "田中部長", "initials": "田."} {"name": "白文正", "family": "白文正", "initials": "白."} {"name": "石智勇", "family": "石智勇", "initials": "石."} {"name": "秦彦三郎", "family": "秦彦三郎", "initials": "秦."} @@ -5617,13 +5622,17 @@ {"name": "陳·陳·怡君·教授,小·達印·博士", "order": "FAMILY_FIRST", "given": "小", "middle": "達印", "family": "陳 陳 怡君", "suffix": "教授, 博士", "initials": "小. 達. 陳. 陳. 怡."} {"name": "陳俊傑", "family": "陳俊傑", "initials": "陳."} {"name": "陳婷", "family": "陳婷", "initials": "陳."} +{"name": "陳子媚 二世", "family": "陳子媚", "suffix": "二世", "initials": "陳."} {"name": "陳子媚先生,小惠儀太平紳士", "order": "FAMILY_FIRST", "given": "小惠儀太平紳士", "family": "陳子媚先生", "initials": "小. 陳."} {"name": "陳子媚惠儀", "order": "FAMILY_FIRST", "family": "陳子媚惠儀", "initials": "陳."} +{"name": "陳怡君 二世", "family": "陳怡君", "suffix": "二世", "initials": "陳."} +{"name": "陳怡君二世", "family": "陳怡君二世", "initials": "陳."} +{"name": "陳怡君,醫學博士", "family": "陳怡君", "suffix": "醫學博士", "initials": "陳."} {"name": "陳明忠", "family": "陳明忠", "initials": "陳."} {"name": "雅婷", "family": "雅婷", "initials": "雅."} {"name": "雅婷", "order": "FAMILY_FIRST", "family": "雅婷", "initials": "雅."} {"name": "雅婷婷婷王", "family": "雅婷婷婷王", "initials": "雅."} -{"name": "雅婷婷婷王二世先生,議員", "given": "議員", "family": "雅婷婷婷王二世先生", "initials": "議. 雅."} +{"name": "雅婷婷婷王二世先生,議員", "family": "雅婷婷婷王二世", "suffix": "先生, 議員", "initials": "雅."} {"name": "雅婷张", "family": "雅婷张", "initials": "雅."} {"name": "雅婷張", "family": "雅婷張", "initials": "雅."} {"name": "雅婷王", "family": "雅婷王", "initials": "雅."} From 4eda2f10c9eae678d33a34cbf9f30d6fc006f264 Mon Sep 17 00:00:00 2001 From: Derek Gulbranson Date: Sat, 17 Oct 2026 14:44:33 -0700 Subject: [PATCH 2/4] Correct the #671 prose after review and pin the surname-split class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the release-log span (2.1, the first release with locales.ZH), drop the 'reversed the name' claim, say the Chinese pack's surname split exposes the words after a listed surname, move the tolerated comma example out of S2, fix stale case notes and comments, and add a row for 李部長. Co-Authored-By: Claude Sonnet 5.5 --- docs/design/decisions.md | 2 +- docs/design/rules.md | 16 +++++++++------- docs/release_log.rst | 2 +- nameparser/config/suffixes.py | 18 ++++++++++-------- tests/v2/cases.py | 22 +++++++++++++++------- tools/differential/corpus_cjk.jsonl | 1 + tools/differential/corpus_rules.jsonl | 1 - tools/differential/snapshot.jsonl | 1 + 8 files changed, 38 insertions(+), 25 deletions(-) diff --git a/docs/design/decisions.md b/docs/design/decisions.md index 428163e8..7ccd6efe 100644 --- a/docs/design/decisions.md +++ b/docs/design/decisions.md @@ -644,7 +644,7 @@ Declined: - 2026-08 #308 — an entry peels only where it can never end a name: 씨/님/さん/様/先生 peel; 양/군/氏/博士/殿 stay spaced-only; 君 is in neither set while its kana spelling くん peels. The vocabulary carries the license, so no structural or per-script gate stands over the peel. - 2026-08 #312 — the peel crosses the family comma and the 间隔号: both answer where a name DIVIDES into surname and given, a question the peel never asks. Provenance matters here: neither gate was argued for the peel specifically — both came with the placement (#312's own framing) — so the crossing was a repair of inherited gates, not a designed-in property. - 2026-08 #319 — a wholly suffix-shaped second run is declined as a peel site (the "田中さん, V." shape), but only when the name's own run offers a site, since a glued honorific is itself part of what makes a run read as suffix-shaped. -- 2026-10-17 #671 — SPACED AND AFTER-COMMA ONLY, no glued peel (Derek, 2026-10-17). 議員/议员, 国会議員/國會議員, 太平紳士/太平绅士, 医学博士/醫學博士, 二世 and the job titles 社長/部長/課長 join `SUFFIX_WORDS`; none joins `GLUED_HONORIFICS`. The spaced bar is only that a word standing alone is no name, so they ship; the glued bar ("can it END a name?") needs real-name counts that this change did not get — the Wikidata suffix query timed out and the 910-name native corpus holds none of the words — and 部長 fails it on argument alone (長 is a borne given name, 阿部長). A follow-up can vet 医学博士, 議員 and 太平紳士 one at a time. Consequence measured on `parser_for(locales.ZH)`: `王二世` reads family 王, suffix 二世 (it read given 二世), because the segmenter's division is not a peel and the split-off 二世 is then a whole-token suffix word, the way 王博士 already reads; `陳怡君二世` still reads given 怡君二世 (glued, nothing divides it). ジュニア was already shipped by #661. Excluded as the issue stated: 小 (a prefix and a common given-name character) and 冯/馮 for "von" (a top-30 surname). +- 2026-10-17 #671 — SPACED AND AFTER-COMMA ONLY, no glued peel (Derek, 2026-10-17). 議員/议员, 国会議員/國會議員, 太平紳士/太平绅士, 医学博士/醫學博士, 二世 and the job titles 社長/部長/課長 join `SUFFIX_WORDS`; none joins `GLUED_HONORIFICS`. The spaced bar is only that a word standing alone is no name, so they ship; the glued bar ("can it END a name?") needs real-name counts that this change did not get — the Wikidata suffix query timed out and the native-script Wikidata corpus holds none of the words — and 部長 fails it on argument alone (長 is a borne given name, 阿部長). A follow-up can vet 医学博士, 議員 and 太平紳士 one at a time. Consequence measured on `parser_for(locales.ZH)`: after a listed surname each word divides off, `王二世` family 王, suffix 二世 (it read given 二世) and `李部長` family 李, suffix 部長, because the segmenter's division is not a peel and the split-off 二世 is then a whole-token suffix word, the way 王博士 already reads; `陳怡君二世` still reads given 怡君二世 (glued, nothing divides it). ジュニア was already shipped by #661, and #679 declined 二世 as CLDR's generation word ("regnal, and glued"); here it ships spaced-only as the Chinese/Japanese numeral, which does not reverse that. Excluded as the issue stated: 小 (a prefix and a common given-name character) and 冯/馮 for "von" (a top-30 surname). Excluded (the never-given / ambiguous particle line, nameparser/config/particles.py — #360 owns the vocabulary question): diff --git a/docs/design/rules.md b/docs/design/rules.md index 973bafcf..9fbada44 100644 --- a/docs/design/rules.md +++ b/docs/design/rules.md @@ -1245,7 +1245,6 @@ S2. Rationale: generational suffixes and credentials are recognized "جورج بوش الابن" → suffix="الابن" "ロバート・ダウニー・ジュニア" → suffix="ジュニア" "佐藤恵子 国会議員" → suffix="国会議員" - "王雅婷,議員" → suffix="議員" "陳子媚 二世" → suffix="二世" "Питер Брейгель мл." → suffix="мл." "Marie Fils" → family="Fils" · boundary @@ -2371,12 +2370,15 @@ W2. Rationale: some East Asian honorifics glue directly onto the end Accepted: the credential, office and generational words of #671 (議員, 国会議員, 太平紳士, 医学博士, 二世, 社長, 部長, 課長 and their variant spellings) are vocabulary in the spaced and after-comma - positions only and are NOT peeled when glued: 陳怡君二世 and - 田中部長 keep the word in the name. The glued bar is "can it END - a name?", and none of these was measured against real names - (部長 fails it outright, 阿部長 being 阿部 + 長). The Han - segmenter's own division is not a peel and can still expose one: - 王二世 under the Chinese pack reads family 王, suffix 二世. + positions only and no peel splits them off a glued name: + 陳怡君二世 and 田中部長 keep the word in the name. The glued bar + is "can it END a name?", and none of these was measured against + real names (部長 fails it outright, 阿部長 being 阿部 + 長). The + Han segmenter's own division is not a peel and still exposes + them: under the Chinese pack a listed surname followed by one of + the words divides there and the word reads as a suffix, so + 王二世 reads family 王, suffix 二世 and 李部長 family 李, suffix + 部長, as 王博士 already does. history: decisions.md#W2 · interacts: W3 · implemented: nameparser/_pipeline/_script_segment.py W3. Rationale: a family name declared by a comma is the writer's diff --git a/docs/release_log.rst b/docs/release_log.rst index 195341ca..2951306b 100644 --- a/docs/release_log.rst +++ b/docs/release_log.rst @@ -8,7 +8,7 @@ Release Log - **Add junior and senior in other languages as suffixes.** ``Antonio Pavlović mlađi`` gives last ``Pavlović``, suffix ``mlađi``, where 1.4.0 through 2.4.2 gave middle ``Pavlović``, last ``mlađi``. The words come from 45 languages and are read when written as a separate word after the name. :issue:`661`, :issue:`679` - **Remove mai from the default post-nominal acronyms, so a trailing Mai keeps the name.** ``Tran Thi Mai`` read in Vietnamese order (``FAMILY_FIRST_GIVEN_LAST``) gives given ``Mai``, middle ``Thi``, family ``Tran``, where 2.0.0 through 2.4.2 gave suffix ``Mai`` and no given name; ``Nguyen Mai`` gives family ``Mai``, as 1.4.0 did. The cost is that ``John Smith MAI`` gives last ``MAI`` instead of suffix; ``Smith, John, MAI`` and ``John Smith M.A.I.`` still read as credentials. A caller who needs it back adds it: ``Lexicon.default().add(suffix_acronyms={"mai"})``. See the ``suffix-acronym-collisions`` entry of ``docs/design/decisions.md`` (:issue:`687`) - - **Add Chinese and Japanese credential, office and generational words as suffixes.** ``彭德威 议员`` under ``locales.ZH`` gives family ``彭``, given ``德威``, suffix ``议员``, where 2.0 through 2.4.2 gave middle ``议员``; ``王雅婷,議員`` gives suffix ``議員``, where it gave given ``議員`` and reversed the name. Read when written as a separate word or after a comma, not glued to the name (``陳怡君二世`` is unchanged). :issue:`671` + - **Add Chinese and Japanese credential, office and generational words as suffixes.** ``彭德威 议员`` under ``locales.ZH`` gives family ``彭``, given ``德威``, suffix ``议员``, where 2.1 through 2.4.2 gave middle ``议员``; ``王雅婷,議員`` gives suffix ``議員``, where it gave given ``議員``. Read when written as a separate word or after a comma; no peel splits them off a glued name (``陳怡君二世`` is unchanged), though the Chinese pack's surname split exposes them after a listed surname (``王二世``). :issue:`671` - **Add the Akan and Indonesian salutations owura and bapak as titles.** ``Bapak Dwi Putro`` gives title ``Bapak``, first ``Dwi``, last ``Putro``, where 1.4.0 through 2.4.2 gave first ``Bapak``, middle ``Dwi``. :issue:`662` * 2.4.2 - October 13, 2026 diff --git a/nameparser/config/suffixes.py b/nameparser/config/suffixes.py index 9950218e..d8478257 100644 --- a/nameparser/config/suffixes.py +++ b/nameparser/config/suffixes.py @@ -170,20 +170,22 @@ # The spaced position is a token boundary the writer drew, so # the vetting bar is just "is a word standing alone ever a # name?"; the glued bar ("can it END a name?") needs real-name - # data this set was not measured against (a Wikidata suffix query - # timed out; the native-script corpus holds none of these words), - # so the glued forms (陳怡君二世, 田中社長) stay unpeeled and - # glued peeling is a separate question. + # data this set was not measured against (decisions.md#W2, #671), + # so no peel splits them off a glued name (陳怡君二世, 田中社長 + # keep the word) and glued peeling is a separate question (#707). + # The Chinese pack's SEGMENTER is not a peel and still exposes + # them after a listed surname: 王二世 and 李部長 divide at the + # surname and the split-off word is then a whole-token suffix + # word, as 王博士 already reads. # - 二世: Japanese/Chinese "II" (the generational numeral). - # 王二世 is read family 王 + given 二世 by the Han segmenter - # today, so the glued form is exactly the open question. # - 議員/议员, 国会議員/國會議員: legislator, Diet member. # - 太平紳士/太平绅士: Justice of the Peace (Hong Kong). # - 医学博士/醫學博士: Doctor of Medicine. # - 社長/部長/課長: Japanese job titles used as forms of address # after a name (田中 社長), not credentials -- the same slot as - # 先生. 部長 is the reason glued is out: 長 alone is a borne - # given name (阿部長 = 阿部 + 長). + # 先生. Japanese spellings only; 社长/部长/课长 are not listed. + # 部長 is the reason glued is out: 長 alone is a borne given + # name (阿部長 = 阿部 + 長). '二世', '議員', '议员', '国会議員', '國會議員', '太平紳士', '太平绅士', diff --git a/tests/v2/cases.py b/tests/v2/cases.py index 4432b33e..f3a8e13f 100644 --- a/tests/v2/cases.py +++ b/tests/v2/cases.py @@ -11483,9 +11483,9 @@ def _check_cjk_shape_purity(self) -> None: Case("ja_spaced_diet_member_is_a_suffix", "佐藤恵子 国会議員", {"family": "佐藤恵子", "suffix": "国会議員"}, classification="fix(#671)", - notes="2.4.2 read given '国会議員', and the unspaced twin " - "moves the same way, so the kana-licensed family-first " - "reading is unchanged"), + notes="2.4.2 read given '国会議員'. The unspaced twin " + "佐藤恵子国会議員 is unchanged (glued, nothing peels it); " + "family-first comes from the wholly-Han script order"), Case("zh_comma_legislator_is_a_suffix", "王雅婷,議員", {"family": "王雅婷", "suffix": "議員"}, classification="fix(#671)", tolerated=True, @@ -11496,8 +11496,8 @@ def _check_cjk_shape_purity(self) -> None: Case("zh_comma_degree_is_a_suffix", "陳怡君,醫學博士", {"family": "陳怡君", "suffix": "醫學博士"}, classification="fix(#671)", tolerated=True, - notes="the degree the glued 博士 exclusion cannot reach: the " - "four-character word is whole after the comma"), + notes="a four-character degree word that is whole after the " + "comma, so the glued-博士 exclusion never applies"), Case("zh_spaced_generational_two_is_a_suffix", "陳怡君 二世", {"family": "陳", "given": "怡君", "suffix": "二世"}, locale="zh", classification="fix(#671)", @@ -11514,13 +11514,21 @@ def _check_cjk_shape_purity(self) -> None: "name (阿部長 = 阿部 + 長), so 部長 is spaced-only. " "Unchanged from 2.4.2, pinned so GLUED_HONORIFICS " "cannot gain it unseen"), + Case("zh_listed_surname_then_new_word_divides", "李部長", + {"family": "李", "suffix": "部長"}, + locale="zh", classification="fix(#671)", + notes="the segmenter divides at the listed surname and the " + "split-off word is a whole-token suffix word, as 王博士 " + "already reads; 2.4.2 read given '部長'. 阿部長 stays " + "whole because 阿 is no listed surname"), Case("zh_glued_generational_two_is_not_peeled", "陳怡君二世", {"family": "陳", "given": "怡君二世"}, locale="zh", classification="fix(#271)", notes="the glued form #671 left open: no peel reads it, " "and 二世 is not vetted against real names. The " - "SEGMENTER's division of 王二世 is another matter -- " - "the pack reads family 王, suffix 二世, because the " + "SEGMENTER's division is another matter: after a " + "listed surname the pack reads 王二世 as family 王, " + "suffix 二世, and 李部長 likewise, because the " "split-off piece is a whole-token suffix word"), Case("zh_glued_jun_stays", "王君", {"family": "王君"}, diff --git a/tools/differential/corpus_cjk.jsonl b/tools/differential/corpus_cjk.jsonl index 7df839b5..9d5cccfa 100644 --- a/tools/differential/corpus_cjk.jsonl +++ b/tools/differential/corpus_cjk.jsonl @@ -54,6 +54,7 @@ "山田タロウ" "张伟" "彭德威 议员" +"李部長" "毛 泽东" "毛 泽东 Dr." "毛 김" diff --git a/tools/differential/corpus_rules.jsonl b/tools/differential/corpus_rules.jsonl index e6e175bf..b5c7c31c 100644 --- a/tools/differential/corpus_rules.jsonl +++ b/tools/differential/corpus_rules.jsonl @@ -548,7 +548,6 @@ "毛·泽东" "毛泽东" "王君" -"王雅婷,議員" "田中 社長" "田中. 太郎" "田中、太郎" diff --git a/tools/differential/snapshot.jsonl b/tools/differential/snapshot.jsonl index 684a3bf9..3734df34 100644 --- a/tools/differential/snapshot.jsonl +++ b/tools/differential/snapshot.jsonl @@ -5500,6 +5500,7 @@ {"name": "李瞻", "family": "李瞻", "initials": "李."} {"name": "李翔", "family": "李翔", "initials": "李."} {"name": "李诗沣", "family": "李诗沣", "initials": "李."} +{"name": "李部長", "family": "李部長", "initials": "李."} {"name": "村田喜一", "family": "村田喜一", "initials": "村."} {"name": "杨扬", "family": "杨扬", "initials": "杨."} {"name": "杨旭", "family": "杨旭", "initials": "杨."} From ccef3d5b68ba36e2a8f6014ae79e8252a74db2e5 Mon Sep 17 00:00:00 2001 From: Derek Gulbranson Date: Sat, 17 Oct 2026 14:50:02 -0700 Subject: [PATCH 3/4] Pin the #671 words structurally: spaced, comma and not glued One parametrized test over all twelve words covers the spelling variants and the comma shapes (one-word and empty head) the rows missed, and a second asserts none is a glued honorific; adding two of them to GLUED_HONORIFICS fails it where six of the twelve passed the suite. Co-Authored-By: Claude Sonnet 5.5 --- tests/v2/test_parser.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/v2/test_parser.py b/tests/v2/test_parser.py index a84f0851..f46c3f5c 100644 --- a/tests/v2/test_parser.py +++ b/tests/v2/test_parser.py @@ -2103,3 +2103,33 @@ def test_a_decomposed_dotted_letter_is_dotted() -> None: differ), so it is pinned directly.""" from nameparser._pipeline._vocab import _dotted assert _dotted(unicodedata.normalize("NFD", "Ž.")) is True + + +# #671: the credential, office and generational words, one spelling each +# per distinct entry. They are spaced / after-comma vocabulary only; the +# glued bar was not met (#707 revisits it), so none may become a glued +# honorific without this list being edited on purpose. +_CJK_SPACED_WORDS = ( + "議員", "议员", "国会議員", "國會議員", "太平紳士", "太平绅士", + "医学博士", "醫學博士", "二世", "社長", "部長", "課長", +) + + +@pytest.mark.parametrize("word", _CJK_SPACED_WORDS) +def test_a_cjk_credential_word_is_a_suffix_spaced_and_after_a_comma( + word: str) -> None: + parser = Parser() + for text in (f"田中 {word}", f"田中, {word}", f"Tanaka, {word}"): + parsed = parser.parse(text) + assert parsed.suffix == word, text + assert word not in parsed.family + parsed.given, text + # a one-word head and an empty head (CSV data with the surname + # missing) are the comma paths that have disagreed before + assert parser.parse(f", {word}").suffix == word + + +@pytest.mark.parametrize("word", _CJK_SPACED_WORDS) +def test_a_cjk_credential_word_does_not_peel_off_a_glued_name( + word: str) -> None: + assert word not in Parser().lexicon.honorific_tails + assert Parser().parse(f"田中{word}").suffix == "" From 4fa21e8dfb7f555879ced1bdbb0e32a76034c019 Mon Sep 17 00:00:00 2001 From: Derek Gulbranson Date: Sat, 17 Oct 2026 17:04:59 -0700 Subject: [PATCH 4/4] =?UTF-8?q?Add=20the=20simplified=20job=20titles=20?= =?UTF-8?q?=E7=A4=BE=E9=95=BF/=E9=83=A8=E9=95=BF/=E8=AF=BE=E9=95=BF=20and?= =?UTF-8?q?=20a=20usage=20note=20on=20glued=20credential=20words?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5.5 --- docs/design/decisions.md | 2 +- docs/usage.rst | 14 ++++++++++++++ nameparser/config/suffixes.py | 11 +++++++---- tests/v2/test_parser.py | 1 + 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/docs/design/decisions.md b/docs/design/decisions.md index 7ccd6efe..52bfa27b 100644 --- a/docs/design/decisions.md +++ b/docs/design/decisions.md @@ -644,7 +644,7 @@ Declined: - 2026-08 #308 — an entry peels only where it can never end a name: 씨/님/さん/様/先生 peel; 양/군/氏/博士/殿 stay spaced-only; 君 is in neither set while its kana spelling くん peels. The vocabulary carries the license, so no structural or per-script gate stands over the peel. - 2026-08 #312 — the peel crosses the family comma and the 间隔号: both answer where a name DIVIDES into surname and given, a question the peel never asks. Provenance matters here: neither gate was argued for the peel specifically — both came with the placement (#312's own framing) — so the crossing was a repair of inherited gates, not a designed-in property. - 2026-08 #319 — a wholly suffix-shaped second run is declined as a peel site (the "田中さん, V." shape), but only when the name's own run offers a site, since a glued honorific is itself part of what makes a run read as suffix-shaped. -- 2026-10-17 #671 — SPACED AND AFTER-COMMA ONLY, no glued peel (Derek, 2026-10-17). 議員/议员, 国会議員/國會議員, 太平紳士/太平绅士, 医学博士/醫學博士, 二世 and the job titles 社長/部長/課長 join `SUFFIX_WORDS`; none joins `GLUED_HONORIFICS`. The spaced bar is only that a word standing alone is no name, so they ship; the glued bar ("can it END a name?") needs real-name counts that this change did not get — the Wikidata suffix query timed out and the native-script Wikidata corpus holds none of the words — and 部長 fails it on argument alone (長 is a borne given name, 阿部長). A follow-up can vet 医学博士, 議員 and 太平紳士 one at a time. Consequence measured on `parser_for(locales.ZH)`: after a listed surname each word divides off, `王二世` family 王, suffix 二世 (it read given 二世) and `李部長` family 李, suffix 部長, because the segmenter's division is not a peel and the split-off 二世 is then a whole-token suffix word, the way 王博士 already reads; `陳怡君二世` still reads given 怡君二世 (glued, nothing divides it). ジュニア was already shipped by #661, and #679 declined 二世 as CLDR's generation word ("regnal, and glued"); here it ships spaced-only as the Chinese/Japanese numeral, which does not reverse that. Excluded as the issue stated: 小 (a prefix and a common given-name character) and 冯/馮 for "von" (a top-30 surname). +- 2026-10-17 #671 — SPACED AND AFTER-COMMA ONLY, no glued peel (Derek, 2026-10-17). 議員/议员, 国会議員/國會議員, 太平紳士/太平绅士, 医学博士/醫學博士, 二世 and the job titles 社長/部長/課長 and the simplified 社长/部长/课长 (Derek, 2026-10-17: the characters are shared and the offices are real in both languages; no borne-name data either way, #707) join `SUFFIX_WORDS`; none joins `GLUED_HONORIFICS`. The spaced bar is only that a word standing alone is no name, so they ship; the glued bar ("can it END a name?") needs real-name counts that this change did not get — the Wikidata suffix query timed out and the native-script Wikidata corpus holds none of the words — and 部長 fails it on argument alone (長 is a borne given name, 阿部長). A follow-up can vet 医学博士, 議員 and 太平紳士 one at a time. Consequence measured on `parser_for(locales.ZH)`: after a listed surname each word divides off, `王二世` family 王, suffix 二世 (it read given 二世) and `李部長` family 李, suffix 部長, because the segmenter's division is not a peel and the split-off 二世 is then a whole-token suffix word, the way 王博士 already reads; `陳怡君二世` still reads given 怡君二世 (glued, nothing divides it). ジュニア was already shipped by #661, and #679 declined 二世 as CLDR's generation word ("regnal, and glued"); here it ships spaced-only as the Chinese/Japanese numeral, which does not reverse that. Excluded as the issue stated: 小 (a prefix and a common given-name character) and 冯/馮 for "von" (a top-30 surname). Excluded (the never-given / ambiguous particle line, nameparser/config/particles.py — #360 owns the vocabulary question): diff --git a/docs/usage.rst b/docs/usage.rst index 760cc59e..071af84d 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -589,6 +589,20 @@ Exactly one honorific peels off a token, and the entries are whole honorifics rather than parts: ``김민준박사님`` gives up 박사님 entire, not 님 with 박사 left behind. +Credential and office words (議員 legislator, 医学博士 doctor of +medicine, 社長 company president, 二世 the second) are recognized in the +spaced form and after a comma only, and are not peeled when glued, +unlike さん. Nobody has checked them against names that end in them, so +the glued form is left whole: + +.. doctest:: + + >>> shacho = parse("田中 社長") + >>> shacho.family, shacho.suffix + ('田中', '社長') + >>> parse("田中社長").family + '田中社長' + When a division was a judgment call ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/nameparser/config/suffixes.py b/nameparser/config/suffixes.py index d8478257..2c93791f 100644 --- a/nameparser/config/suffixes.py +++ b/nameparser/config/suffixes.py @@ -181,16 +181,19 @@ # - 議員/议员, 国会議員/國會議員: legislator, Diet member. # - 太平紳士/太平绅士: Justice of the Peace (Hong Kong). # - 医学博士/醫學博士: Doctor of Medicine. - # - 社長/部長/課長: Japanese job titles used as forms of address - # after a name (田中 社長), not credentials -- the same slot as - # 先生. Japanese spellings only; 社长/部长/课长 are not listed. + # - 社長/部長/課長 and the simplified 社长/部长/课长: job titles + # used as forms of address after a name (田中 社長, 李部长), + # not credentials -- the same slot as 先生. Japanese president, + # department head, section chief; Chinese society head, + # minister, section chief. The simplified 长 never occurs in + # Japanese text, so those entries touch no Japanese name. # 部長 is the reason glued is out: 長 alone is a borne given # name (阿部長 = 阿部 + 長). '二世', '議員', '议员', '国会議員', '國會議員', '太平紳士', '太平绅士', '医学博士', '醫學博士', - '社長', '部長', '課長', + '社長', '部長', '課長', '社长', '部长', '课长', # #346/#344/#343: spaced trailing honorifics, South Asian and # Tibetan. SPACED ONLY -- none of these is in GLUED_HONORIFICS # below, and none may be added to it. जी is the reason and the diff --git a/tests/v2/test_parser.py b/tests/v2/test_parser.py index f46c3f5c..eeb7de2d 100644 --- a/tests/v2/test_parser.py +++ b/tests/v2/test_parser.py @@ -2112,6 +2112,7 @@ def test_a_decomposed_dotted_letter_is_dotted() -> None: _CJK_SPACED_WORDS = ( "議員", "议员", "国会議員", "國會議員", "太平紳士", "太平绅士", "医学博士", "醫學博士", "二世", "社長", "部長", "課長", + "社长", "部长", "课长", )