Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/release_log.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Release Log
- Fix the katakana middle dot ``・`` (U+30FB, and its halfwidth twin U+FF65) being read as part of a name rather than as the divider it is: it now separates tokens exactly as a space does. A transcribed foreign name therefore divides into its parts and, being wholly katakana, keeps its source order — ``"マイケル・ジャクソン"`` gives given ``マイケル``, family ``ジャクソン``, where 1.x left the whole string in ``first`` — while a kanji pair written the same way takes the family-first rule (``"高橋・一郎"`` → family ``高橋``). Native Japanese names never contain this character and no other script's names use it, so the separation is unconditional, which also means it is **not** covered by the two policy opt-outs. Rendering follows, the way the Korean split's does: the dot comes back as a space, so ``str(HumanName("マイケル・ジャクソン"))`` is now ``"マイケル ジャクソン"``, and that reaches delimited content too — the nickname in ``"山田 太郎 (マイケル・ジャクソン)"`` renders ``"マイケル ジャクソン"``. The Chinese interpunct ``·`` is not an unconditional separator like these two: U+00B7 is also the Catalan punt volat and appears inside legitimate names (``Gal·la``), so it divides only between classified-script characters — the transcription treatment it marks is #298's (#272)
- Fix 间隔号-divided transcriptions parsing as one unsplit token: U+00B7 — the interpunct Chinese text divides a transcribed foreign name with, ``威廉·莎士比亚`` for William Shakespeare — is now a token separator between characters of a classified script, and a name it divides keeps its source order and is never segmented: the dot is the transcription marker, playing the role pure katakana plays in the kana license. It divides ONLY between classified-script characters, so the Catalan punt volat interior to names like ``Gal·la`` is untouched. The Japanese nakaguro is deliberately not a transcription marker — ``高橋・一郎`` is roster formatting, 姓・名, and keeps its family-first reading — so a transcription typed with the wrong dot (``威廉・莎士比亚``) reads by the convention of the codepoint it was typed with; like the spaced form, only the Chinese dot rescues it. Rendering stays space-joined (``str(HumanName("威廉·莎士比亚"))`` is ``"威廉 莎士比亚"``); a custom ``string_format`` such as ``"{first}·{last}"`` reinstates the dot (#298)
- Fix NFD-decomposed input missing the East Asian defaults entirely: script classification now normalizes to NFC before deciding, so a Korean or Japanese name typed on macOS — where decomposed text is routine — gets the same order rule as its composed twin, which it silently did not before. Segmentation MATCHING deliberately stays raw, so an unspaced NFD hangul name is ordered correctly but not split, rather than being split in the wrong place. One gotcha worth stating plainly: parse output preserves the encoding it was given, so for NFD input ``name.family == "김"`` is ``False`` even though it is the same name — compare NFC-normalized text when comparing across encodings (#272)
- Fix the Ukrainian conjunction ``й`` not joining the pieces around it: it is the euphonic alternate of ``і``, the two chosen by the surrounding vowel and consonant rather than by meaning (``"Олесь і Олена"`` but ``"Марія й Петро"``), so real Ukrainian data carries both spellings and shipping only ``і`` recognized just one of them. ``"Олесь й Олена Коваленки"`` now gives given ``"Олесь й Олена"`` where the ``й`` previously landed in ``middle``. Same treatment as the ``и``/``і`` entries added in 2.0.0, single-letter carve-out included: the conjunction joins only once the name has enough pieces, and a punctuated initial still wins, so ``"Й. Сліпий"`` is unaffected. Raised in a comment on #267

* 2.0.0 - July 27, 2026

Expand Down
6 changes: 5 additions & 1 deletion nameparser/config/conjunctions.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@
'the',
'und',
'y',
# #269: Cyrillic (ru/uk/bg) "and": и, і, та.
# #269: Cyrillic (ru/uk/bg) "and": и, і, та. Ukrainian writes і and
# й for the same conjunction, alternating on the surrounding
# vowel/consonant for euphony ("Олесь і Олена", "Марія й Петро"),
# so real data carries both spellings and neither alone suffices.
'и',
'і',
'й',
'та',
# #269: Greek "and": και.
'και',
Expand Down
25 changes: 25 additions & 0 deletions tests/v2/test_locales.py
Original file line number Diff line number Diff line change
Expand Up @@ -931,6 +931,16 @@ def test_non_interference_all_packs_combined() -> None:
# Ukrainian "і" is single-character like "и", so the same
# single-letter carve-out applies: pinned with a 5-piece name.
("проф і акад Тарас Григорович Шевченко", "title", "проф і акад"),
# Ukrainian "й" is the euphonic alternate of "і" (the two swap by
# surrounding vowel/consonant, so real data carries both) -- same
# single-letter carve-out, pinned with the same 5-piece shape.
("проф й акад Тарас Григорович Шевченко", "title", "проф й акад"),
# ...and joining two given names, the shape #267's reporter raised:
# a bare Cyrillic letter between given names reads as the
# conjunction, not an initial (Cyrillic typography writes initials
# with periods -- see
# test_267_dotted_cyrillic_initial_wins_over_conjunction).
("Олесь й Олена Коваленки", "given", "Олесь й Олена"),
# Greek titles + conjunction (και has 3 letters, so the single-char
# initial carve-out above never applies to it). Bare κ is NOT
# shipped -- it collides with the initial+surname shape (see the
Expand Down Expand Up @@ -1075,3 +1085,18 @@ def test_269_bare_greek_kappa_not_a_title() -> None:
assert n.title == ""
assert n.given == "Κ."
assert n.family == "Παπαδόπουλος"


def test_267_dotted_cyrillic_initial_wins_over_conjunction() -> None:
# Blast-radius guard for the single-letter Cyrillic conjunctions
# (и/і/й): each is also the first letter of real given names
# (Игорь, Ірина, Йосип), so the shipped entries would be a trap if
# membership could outrank a punctuated initial. It cannot -- the
# initial regex's dotted branch is Unicode-aware -- and #267 settled
# the BARE letter in the conjunction's favor precisely because
# Cyrillic typography writes initials with the period.
for dotted, family in (("И.", "Иванов"), ("І.", "Франко"),
("Й.", "Сліпий")):
n = parse(f"{dotted} {family}")
assert n.given == dotted
assert n.family == family