Skip to content

Commit b20059b

Browse files
derek73claude
andcommitted
docs: show the customizations that only had table rows
v1's customize.rst carried ~109 doctest lines; the 2.0 rewrite kept 31. Prose survived better than code did, leaving six capabilities described but never demonstrated. Each of these exists and works; only the example was missing. - bound_given_names had exactly one mention in all of 2.0's docs, a rename row in migrate.rst. That is the entire Arabic given-name feature, invisible to anyone not migrating from v1. Show the default, adding one, and emptying the set to switch it off; note the shipped set now includes Arabic-script spellings, not just transliterations. - particles_ambiguous gets the before/after that makes the flip concrete: "van Gogh" keeps given='van' because van may be a given name, "de Mesnil" has no given name at all because de may not. That second rule — a name starting with a never-given particle is entirely surname — was documented nowhere. - extra_suffix_delimiters, additive nickname delimiters, and the strip flags each get the unconfigured parse first. Seeing "Jane Smith, RN - CRNA" come back as given='RN', family='Jane Smith' is the reason a reader goes looking for the setting; the table row alone never conveyed that. The additive-delimiter example also warns about replacing the defaults, the same trap already flagged for capitalization_exceptions. - usage.rst gains v1's sorting recipe: family_base is the key you want for alphabetizing, since it drops the particles a phone book ignores. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent b20e1cd commit b20059b

2 files changed

Lines changed: 102 additions & 0 deletions

File tree

docs/customize.rst

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,54 @@ a suffix only when written with periods:
129129
>>> parse("Jack M.A.").suffix
130130
'M.A.'
131131

132+
``particles_ambiguous`` is the same idea for surname particles. A
133+
particle listed there may also be a given name, so a name that starts
134+
with one keeps its given name; a particle *not* listed there is never a
135+
given name, so a name starting with it has no given name at all — the
136+
whole thing is the surname:
137+
138+
.. doctest::
139+
140+
>>> parse("van Gogh").given # 'van' may be a given name
141+
'van'
142+
>>> parse("de Mesnil").given # 'de' may not
143+
''
144+
>>> parse("de Mesnil").family
145+
'de Mesnil'
146+
147+
If your data never uses ``Van`` as a given name, take it out of the
148+
ambiguous set and leading ``van`` becomes part of the surname:
149+
150+
.. doctest::
151+
152+
>>> lex = Lexicon.default().remove(particles_ambiguous={"van"})
153+
>>> Parser(lexicon=lex).parse("van Gogh").family
154+
'van Gogh'
155+
156+
Bound given names
157+
~~~~~~~~~~~~~~~~~~
158+
159+
``bound_given_names`` holds given-name prefixes that attach to the
160+
following word to form one given name — ``abdul``, ``abu``, ``umm`` and
161+
their Arabic-script spellings (``عبد``, ``أبو``, ``أم``) among them:
162+
163+
.. doctest::
164+
165+
>>> parse("abdul salam ahmed salem").given
166+
'abdul salam'
167+
168+
Add your own, or empty the set to switch the behavior off entirely:
169+
170+
.. doctest::
171+
172+
>>> lex = Lexicon.default().add(bound_given_names={"mohamad"})
173+
>>> Parser(lexicon=lex).parse("mohamad salam ahmed salem").given
174+
'mohamad salam'
175+
>>> d = Lexicon.default()
176+
>>> off = d.remove(bound_given_names=set(d.bound_given_names))
177+
>>> Parser(lexicon=off).parse("abdul salam ahmed salem").given
178+
'abdul'
179+
132180
Behavior: Policy
133181
-----------------
134182

@@ -226,6 +274,50 @@ family-then-given regardless of the configured order:
226274
>>> Parser(policy=policy).parse("Jane (Jones) Smith").maiden
227275
'Jones'
228276

277+
To *add* a delimiter pair rather than reroute one, build on the
278+
exported default — assigning a bare set replaces the built-in pairs
279+
instead of extending them, the same trap as ``capitalization_exceptions``:
280+
281+
.. doctest::
282+
283+
>>> from nameparser import DEFAULT_NICKNAME_DELIMITERS
284+
>>> parse("Benjamin {Ben} Franklin").middle # not a pair by default
285+
'{Ben}'
286+
>>> policy = Policy(
287+
... nickname_delimiters=DEFAULT_NICKNAME_DELIMITERS | {("{", "}")})
288+
>>> Parser(policy=policy).parse("Benjamin {Ben} Franklin").nickname
289+
'Ben'
290+
291+
``extra_suffix_delimiters`` handles sources that separate post-nominals
292+
with something other than a comma. The default reading of such a name
293+
is bad enough to be the reason you'd go looking:
294+
295+
.. doctest::
296+
297+
>>> name = parse("Jane Smith, RN - CRNA")
298+
>>> name.given, name.family, name.suffix
299+
('RN', 'Jane Smith', 'CRNA')
300+
>>> policy = Policy(extra_suffix_delimiters={" - "})
301+
>>> name = Parser(policy=policy).parse("Jane Smith, RN - CRNA")
302+
>>> name.given, name.family, name.suffix
303+
('Jane', 'Smith', 'RN, CRNA')
304+
305+
The strip flags keep characters the parser removes by default. Note
306+
what happens to an emoji you keep — it becomes a token like any other,
307+
and lands in the middle name:
308+
309+
.. doctest::
310+
311+
>>> str(parse("Sam 😊 Smith")) # stripped by default
312+
'Sam Smith'
313+
>>> kept = Parser(policy=Policy(strip_emoji=False)).parse("Sam 😊 Smith")
314+
>>> str(kept), kept.middle
315+
('Sam 😊 Smith', '😊')
316+
317+
``strip_bidi=False`` does the same for invisible bidirectional control
318+
characters, which is occasionally what you want when round-tripping
319+
right-to-left text verbatim.
320+
229321
A pair routes to exactly one field, and ``maiden_delimiters`` states
230322
the specific intent — so listing a pair there automatically drops it
231323
from the effective ``nickname_delimiters`` set, and the one-liner

docs/usage.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,16 @@ while ``given_names`` and ``surnames`` roll several fields together —
6666
the same sense in which a passport form asks for your "given names" as
6767
one blank that can hold more than one word.
6868

69+
``family_base`` is what you want for alphabetizing, since it drops the
70+
particles a phone book ignores:
71+
72+
.. doctest::
73+
74+
>>> names = [parse(s) for s in
75+
... ["Vincent van Gogh", "Juan de la Vega", "John Smith"]]
76+
>>> [n.family_base for n in sorted(names, key=lambda n: n.family_base.lower())]
77+
['Gogh', 'Smith', 'Vega']
78+
6979
Dicts and strings
7080
------------------
7181

0 commit comments

Comments
 (0)