diff --git a/docs/customize.rst b/docs/customize.rst index a34341b..115f2b0 100644 --- a/docs/customize.rst +++ b/docs/customize.rst @@ -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 @@ -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 +`_). + +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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/tests/v2/test_parser.py b/tests/v2/test_parser.py index 7bfd5e5..6cfb7cf 100644 --- a/tests/v2/test_parser.py +++ b/tests/v2/test_parser.py @@ -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