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
19 changes: 18 additions & 1 deletion nameparser/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,23 @@ def are_suffixes(self, pieces: Iterable[str]) -> bool:
return False
return True

def are_suffixes_after_comma(self, pieces: Iterable[str]) -> bool:
"""Like are_suffixes, but pieces found in suffix_not_acronyms are
accepted unconditionally without passing through is_suffix().

Used when detecting suffix-comma format (e.g. "John Ingram, V") where
the post-comma position is unambiguous. This covers all
suffix_not_acronyms members (i, ii, iii, iv, v, jr, sr, etc.),
case-insensitively, including single-letter entries that is_suffix()
would otherwise reject via is_an_initial().
"""
for piece in pieces:
if lc(piece) in self.C.suffix_not_acronyms:
continue
if not self.is_suffix(piece):
return False
return True

def is_rootname(self, piece: str) -> bool:
"""
Is not a known title, suffix or prefix. Just first, middle, last names.
Expand Down Expand Up @@ -686,7 +703,7 @@ def parse_full_name(self) -> None:

post_comma_pieces = self.parse_pieces(parts[1].split(' '), 1)

if self.are_suffixes(parts[1].split(' ')) \
if self.are_suffixes_after_comma(parts[1].split(' ')) \
and len(parts[0].split(' ')) > 1:

# suffix comma:
Expand Down
29 changes: 29 additions & 0 deletions tests/test_suffixes.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,35 @@ def test_two_suffixes_lastname_comma_format(self) -> None:
# NOTE: this adds a comma when the original format did not have one.
self.m(hn.suffix, "Jr., MD", hn)

def test_roman_numeral_v_suffix_comma_format(self) -> None:
# suffix-comma position is unambiguous: 'V' must be a suffix, not a single-letter initial
hn = HumanName("John W. Ingram, V")
self.m(hn.first, "John", hn)
self.m(hn.middle, "W.", hn)
self.m(hn.last, "Ingram", hn)
self.m(hn.suffix, "V", hn)

def test_roman_numeral_i_suffix_comma_format(self) -> None:
# 'I' has the same single-letter ambiguity as 'V'
hn = HumanName("John W. Smith, I")
self.m(hn.first, "John", hn)
self.m(hn.middle, "W.", hn)
self.m(hn.last, "Smith", hn)
self.m(hn.suffix, "I", hn)

def test_suffix_not_acronym_then_acronym_suffix_comma_format(self) -> None:
# single-letter suffix_not_acronyms entry followed by an acronym suffix
hn = HumanName("John Smith, V MD")
self.m(hn.first, "John", hn)
self.m(hn.last, "Smith", hn)
self.m(hn.suffix, "V MD", hn)

def test_two_suffix_not_acronyms_suffix_comma_format(self) -> None:
hn = HumanName("John Smith, V Jr.")
self.m(hn.first, "John", hn)
self.m(hn.last, "Smith", hn)
self.m(hn.suffix, "V Jr.", hn)

def test_two_suffixes_suffix_comma_format(self) -> None:
hn = HumanName("Franklin Washington, Jr. MD")
self.m(hn.first, "Franklin", hn)
Expand Down