Skip to content

Commit 18fbb2e

Browse files
committed
Guard comma split against a custom regexes dict missing "commas"
RegexTupleManager falls back to EMPTY_REGEX for any key absent from a custom regexes dict, and re.compile('').split() matches between every character rather than not splitting -- so a Constants built with a custom regexes set that omits "commas" shattered names into single characters instead of just disabling the comma split. Also clarifies the suffix_delimiter docstring to mention the comma variants. Found in review of #281.
1 parent 1a7f418 commit 18fbb2e

3 files changed

Lines changed: 30 additions & 4 deletions

File tree

nameparser/config/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -590,8 +590,9 @@ class Constants:
590590
``None`` (no additional splitting beyond the standard comma split).
591591
592592
Note: setting this to ``","`` or ``", "`` has no additional effect —
593-
the full name is already split on bare commas first, and each resulting
594-
part is stripped of surrounding whitespace before this step runs.
593+
the full name is already split on comma characters first (including the
594+
Arabic ``،`` and fullwidth ``,`` variants), and each resulting part is
595+
stripped of surrounding whitespace before this step runs.
595596
596597
The delimiter is only applied to parts once they've been identified as
597598
a suffix group, so it never leaks into a first- or middle-name part. For

nameparser/parser.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1195,8 +1195,14 @@ def parse_full_name(self) -> None:
11951195

11961196
self._full_name = self.collapse_whitespace(self._full_name)
11971197

1198-
# break up full_name by commas
1199-
parts = [x.strip() for x in self.C.regexes.commas.split(self._full_name)]
1198+
# break up full_name by commas. A missing "commas" key in a custom
1199+
# regexes dict falls back to RegexTupleManager's EMPTY_REGEX, whose
1200+
# .split() matches between every character rather than not
1201+
# splitting at all -- guard against that so a custom regexes dict
1202+
# that omits "commas" disables the comma split instead of shattering
1203+
# the name into single characters.
1204+
commas = self.C.regexes.commas
1205+
parts = [x.strip() for x in (commas.split(self._full_name) if commas.pattern else [self._full_name])]
12001206
self._had_comma = len(parts) > 1
12011207

12021208
log.debug("full_name: %s", self._full_name)

tests/test_comma_variants.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
from nameparser import HumanName
2+
from nameparser.config import Constants
3+
from nameparser.config.regexes import REGEXES
24

35
from tests.base import HumanNameTestBase
46

@@ -26,3 +28,20 @@ def test_trailing_arabic_comma_stripped(self) -> None:
2628
# nothing after the comma, so it's a bare name, not "Last,"
2729
hn = HumanName("سلمان،")
2830
self.m(hn.first, "سلمان", hn)
31+
32+
def test_custom_regexes_without_commas_key_does_not_shatter_name(self) -> None:
33+
# A custom regexes dict that omits "commas" entirely must not fall
34+
# back to RegexTupleManager's EMPTY_REGEX default for splitting --
35+
# re.compile('').split(...) matches between every character, which
36+
# explodes any name into single-char pieces instead of leaving it
37+
# unsplit (the EMPTY_REGEX convention elsewhere in this codebase
38+
# means "feature disabled", not "split on every character").
39+
# With comma splitting disabled, "Smith, John" is tokenized like any
40+
# other no-comma input (word tokenizing drops the punctuation),
41+
# yielding a plain first/last pair -- not the inverted "Last, First"
42+
# reading, and definitely not single-character pieces.
43+
custom = {k: v for k, v in REGEXES.items() if k != 'commas'}
44+
c = Constants(regexes=custom)
45+
hn = HumanName("Smith, John", constants=c)
46+
self.m(hn.first, "Smith", hn)
47+
self.m(hn.last, "John", hn)

0 commit comments

Comments
 (0)