1from nameparser.config._invariants import assert_normalized
2
3MAIDEN_MARKERS = frozenset({
4 'née',
5 'né',
6 'nee',
7 'geb',
8 'geborene',
9 'geboren',
10 'rozená',
11 'født',
12 'fødd',
13 'född',
14 'урожд',
15 'урождённая',
16 'урожденная',
17 'урождённый',
18 'урожденный',
19 'z domu',
20 '旧姓',
21})
22"""
23Markers that introduce a birth surname, e.g. "Jane Smith née Jones"
24(#274). French née/né/nee, German geb./geborene, Dutch geboren,
25Czech/Slovak rozená, Danish/Norwegian født (Nynorsk fødd), Swedish
26född, Russian урожд./урождённая/урождённый (both ё and е spellings —
27case normalization does not fold them, and running text routinely
28writes е), and Polish "z domu" (#434). Both grammatical genders are
29listed where #274 or review attested them (née/né,
30урождённая/урождённый); Czech masculine rozený awaits the same
31vetting, and would be vetted on its own merits rather than following
32the feminine form in — the abbreviation roz. shared by both genders is
33deliberately absent, below. Entries are stored normalized: lowercase,
34no periods.
35
36An entry may be a PHRASE, and "z domu" ("of the house") is the first
37one shipped. Phrases are stored space-joined and folded per word, and
38matched by lookahead, longest first, over a run of whole tokens that
39stand TOGETHER -- a phrase divided by a bracketed clause or a comma is
40not that phrase, so "Anna z (domu) Nowak" keeps its family name just as
41"Anna z Nowak" does. That mechanism is what makes this entry safe where
42its words are not: z is an ordinary Polish preposition and domu an
43ordinary noun, and the whole-phrase claim never fires on either alone.
44Splitting a phrase into its words is what the library used to advise
45(the dead-entry warning, which no longer fires for this field), and it
46produced exactly the misreadings the phrase avoids:
47maiden "domu Nowak" for "Maria Kowalska z domu Nowak", and no family
48name at all for "Anna z Nowak". A caller who added z and domu
49separately should remove both and let the shipped entry work.
50
51Japanese 旧姓 is here rather than in locales.JA, on the rule that
52admitted the Cyrillic entries: a native-script marker cannot collide
53with a Latin-script name, and matching is whole-token, so it is safe
54as a default. (Whole-token is still the rule for a phrase entry: it
55claims a run of whole tokens, one per word, and no part of one.)
56Neither character appears in any shipped surname, title, suffix,
57conjunction, particle or bound-given vocabulary. locales.JA
58is for what needs the my-data-is-Japanese declaration -- segmentation,
59where a pure-Han string cannot say which language wrote it -- and this
60needs none, since it can only ever match Han text.
61
62Matching being whole-token, the marker has to BE a token -- which for
63Japanese means something has to divide it from the name it marks. A
64space does, and so does a delimiter: extract masks the whole bracketed
65region, delimiter characters included, before tokenize runs, so a
66bracket bounds a token exactly as a space does and "山田(旧姓 佐藤)"
67needs no space in front of 旧姓 at all. The bare "山田花子 旧姓 佐藤"
68and the bracketed "山田 花子(旧姓 佐藤)" alike give maiden 佐藤, and
69since #335 the bracketed form needs no configuration to do it: the
70fullwidth pair is a NICKNAME delimiter by default, and rules.md#M3
71reads a clause that opens with a marker word AND carries a word after
72it as the maiden name, whichever bucket its pair sits in. The second
73word is part of the condition, not a detail of it -- a lone "(旧姓)"
74is a word in brackets and stays a nickname. #329, which drops the marker from inside the
75clause, is what makes the value 佐藤 rather than "旧姓 佐藤". Declaring
76the pair in Policy(maiden_delimiters=...) reaches the same reading by
77M1's path. What divides nothing is the fullwidth colon that the form
78Japanese more often writes puts after the marker: "山田(旧姓:佐藤)"
79under Policy(maiden_delimiters=...) still yields maiden "旧姓:佐藤"
80with the marker and its colon attached. Not because delimited content
81escapes classification -- classify tags a marker wherever it is a
82token -- but because : is no separator tokenize knows, so marker and
83name arrive as ONE token and there is nothing to drop. M3 does not
84reach that form either, and by its own test rather than by tokenize's:
85it splits the clause on WHITESPACE, and "旧姓:佐藤" is one whitespace
86word, so there is no marker word for the clause to open with and by
87default it stays a nickname. The two tests agree here and are
88deliberately not the same test -- see decisions.md#M3. The wholly
89unspaced "山田花子(旧姓佐藤)" reads as one token for the same reason.
90Peeling a marker off the head of a token is #317's job.
91
92Consumed by the 2.0 parser's default lexicon. The 1.x parser does not
93read this module.
94
95Deliberately absent: the Scandinavian
96abbreviation "f." (collides with the initial "F." — only the full
97participles are safe), and the Czech/Slovak abbreviation "roz."
98(shipped through 2.1 and removed in 2.2). Roz is an ordinary English
99diminutive of Rosalind, and matching is whole-token, case-folded and
100period-insensitive, so "Roz", "roz" and "roz." are one string to this
101set: with it shipped, "Rosalind Roz Smith" read maiden "Smith" and NO
102family name at all. The collision is in the position the claim acts
103on, which is the test decisions.md#vocabulary-collisions states, and
104this set has no ambiguous subset to express a partial answer in — see
105decisions.md's Excluded (MAIDEN_MARKERS) block. The full participle
106rozená stays, being unambiguous; a caller who needs the abbreviation
107adds it to their own Lexicon.
108"""
109
110
111assert_normalized("MAIDEN_MARKERS", MAIDEN_MARKERS)