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
49 changes: 40 additions & 9 deletions docs/customize.rst
Original file line number Diff line number Diff line change
Expand Up @@ -296,20 +296,20 @@ without going through a locale pack -- call :meth:`Policy.patched()
Family-first name order
~~~~~~~~~~~~~~~~~~~~~~~~

``name_order`` is the one most likely to matter for non-Western data.
Positional input is assigned in the order you declare, so a
family-first name parses as written instead of needing to be
rearranged afterwards:
``name_order`` is the one most likely to matter for data that is not
in Western order. Positional input is assigned in the order you
declare, so a name written family-first — Hungarian, here — parses as
written instead of needing to be rearranged afterwards:

.. doctest::

>>> from nameparser import Parser, Policy, FAMILY_FIRST, parse
>>> parse("Nguyen Van Minh").family # default GIVEN_FIRST
'Van Minh'
>>> parse("Nagy Laszlo Peter").family # default GIVEN_FIRST
'Peter'
>>> family_first = Parser(policy=Policy(name_order=FAMILY_FIRST))
>>> name = family_first.parse("Nguyen Van Minh")
>>> name.family, name.given
('Nguyen', 'Van Minh')
>>> name = family_first.parse("Nagy Laszlo Peter")
>>> name.family, name.given, name.middle
('Nagy', 'Laszlo', 'Peter')

An explicit comma still wins, on the reasoning that someone who wrote
one meant it — so the same parser reads ``"Thomas, John"`` as
Expand All @@ -320,6 +320,37 @@ family-then-given regardless of the configured order:
>>> family_first.parse("Thomas, John").family
'Thomas'

A Vietnamese full name needs a third order. It is written family, then
middle, then given — the name a person is actually called by is the
*last* word, not the second. Family-first order gets the family name
right and then reverses the remaining two, so
``FAMILY_FIRST_GIVEN_LAST`` exists for the names that read this way:

.. doctest::

>>> from nameparser import FAMILY_FIRST_GIVEN_LAST
>>> family_first.parse("Tran Quoc Toan").given # FAMILY_FIRST
'Quoc'
>>> given_last = Parser(policy=Policy(name_order=FAMILY_FIRST_GIVEN_LAST))
>>> viet = given_last.parse("Tran Quoc Toan")
>>> viet.family, viet.middle, viet.given
('Tran', 'Quoc', 'Toan')

Nothing keys this order to a script the way the East Asian defaults
below do — Vietnamese is written in the Latin alphabet, which carries
no order of its own — so it applies only where you set it, and there
is no ``vn`` locale pack yet (issue `#146
<https://github.com/derek73/python-nameparser/issues/146>`_).

One caution, which is why the example above is not the more obvious
``"Nguyen Van Minh"``: a middle word that is also a shipped particle
is claimed by the vocabulary layer before ``name_order`` is consulted
at all. ``Van`` is the Dutch particle ``van``, so that name reads
family ``Nguyen`` with ``Van Minh`` given under *both* family-first
orders, and the choice between them makes no difference. `Words that
are also ordinary names`_ covers dropping such a word from the
vocabulary.

East Asian defaults, and turning them off
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down
10 changes: 10 additions & 0 deletions tests/v2/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,16 @@ def test_family_first_given_last_places_middle_between() -> None:
assert (pn.family, pn.middle, pn.given) == ("Zeng", "Xiao", "Long")


def test_ambiguous_particle_middle_defeats_both_family_first_orders() -> None:
# the vocabulary layer joins the ambiguous particle "van" forward
# before the positional layer runs, so a name whose middle word
# collides with it parses identically under either family-first
# order -- the caution in customize.rst rests on this
for order in (FAMILY_FIRST, FAMILY_FIRST_GIVEN_LAST):
pn = Parser(policy=Policy(name_order=order)).parse("Nguyen Van Minh")
assert (pn.family, pn.middle, pn.given) == ("Nguyen", "", "Van Minh")


def test_multiple_unbalanced_delimiters_each_reported() -> None:
# T4: the extract scan continues past the first unmatched opener;
# each one is reported and treated as literal text
Expand Down