Skip to content

Commit f5d383e

Browse files
derek73claude
andcommitted
fix: recognize trailing suffix_not_acronyms in lastname-comma format (closes #144)
In 'Last, First Middle I' format, a trailing single-letter suffix like 'I' was silently absorbed into the middle name because is_suffix() rejects single uppercase letters via is_an_initial(). Add is_suffix_at_lastname_comma_end() which applies when the piece is the final token of the post-comma segment and no explicit comma-separated suffix follows (len(parts)==2). When parts[2] exists the caller already declared a suffix, making the trailing token more likely a middle initial (e.g. 'Doe, Rev. John V, Jr.'), so that case is excluded. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 8d5f769 commit f5d383e

2 files changed

Lines changed: 23 additions & 1 deletion

File tree

nameparser/parser.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,20 @@ def are_suffixes_after_comma(self, pieces: Iterable[str]) -> bool:
504504
return False
505505
return True
506506

507+
def is_suffix_at_lastname_comma_end(self, piece: str, nxt: str | None, parts: list[str]) -> bool:
508+
"""True when a suffix_not_acronyms member is the final token in the
509+
post-comma segment of a lastname-comma name with no explicit
510+
comma-separated suffix (e.g. 'Maier, Amy Lauren I').
511+
512+
When parts[2] exists the caller already has an explicit suffix, making
513+
the trailing single-letter more likely a middle initial
514+
(e.g. 'Doe, Rev. John V, Jr.'), so the guard len(parts)==2 excludes
515+
that case.
516+
"""
517+
return (nxt is None
518+
and len(parts) == 2
519+
and lc(piece) in self.C.suffix_not_acronyms)
520+
507521
def is_rootname(self, piece: str) -> bool:
508522
"""
509523
Is not a known title, suffix or prefix. Just first, middle, last names.
@@ -767,7 +781,7 @@ def parse_full_name(self) -> None:
767781
if not self.first:
768782
self.first_list.append(piece)
769783
continue
770-
if self.is_suffix(piece):
784+
if self.is_suffix(piece) or self.is_suffix_at_lastname_comma_end(piece, nxt, parts):
771785
self.suffix_list.append(piece)
772786
continue
773787
self.middle_list.append(piece)

tests/test_suffixes.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,14 @@ def test_suffix_with_periods_with_lastname_comma(self) -> None:
166166
self.m(hn.last, "Doe", hn)
167167
self.m(hn.suffix, "Msc.Ed.", hn)
168168

169+
def test_roman_numeral_i_lastname_comma_format(self) -> None:
170+
# trailing 'I' in lastname-comma format must be a suffix, not a middle initial (issue #144)
171+
hn = HumanName("Maier, Amy Lauren I")
172+
self.m(hn.first, "Amy", hn)
173+
self.m(hn.middle, "Lauren", hn)
174+
self.m(hn.last, "Maier", hn)
175+
self.m(hn.suffix, "I", hn)
176+
169177
def test_suffix_delimiter_default_on_constants(self) -> None:
170178
from nameparser.config import CONSTANTS
171179
self.assertIs(CONSTANTS.suffix_delimiter, None)

0 commit comments

Comments
 (0)