From 41687ebd7df1faf8bdd486c0af8e432c987c8035 Mon Sep 17 00:00:00 2001 From: DeviousStoat Date: Fri, 3 Jul 2026 12:11:34 +0200 Subject: [PATCH] stricter numbered highway parsing --- pyap/source_US/data.py | 132 +++++++++++++++++++++------------------- tests/test_parser.py | 11 ++++ tests/test_parser_us.py | 2 + 3 files changed, 82 insertions(+), 63 deletions(-) diff --git a/pyap/source_US/data.py b/pyap/source_US/data.py index 39ee827..0d0493e 100644 --- a/pyap/source_US/data.py +++ b/pyap/source_US/data.py @@ -110,76 +110,82 @@ def str_list_to_upper_lower_regex(str_list: List[str]) -> str: from_to="{1,5}", ) +STATE_ABBRS = ( + "AL", + "AK", + "AZ", + "AR", + "CA", + "CO", + "CT", + "DE", + "FL", + "GA", + "HI", + "ID", + "IL", + "IN", + "IA", + "KS", + "KY", + "LA", + "ME", + "MD", + "MA", + r"MI(?:CH)?\.?", + "MN", + "MS", + "MO", + "MT", + "NE", + "NV", + "NH", + "NJ", + "NM", + r"NY|N\.Y\.", + "NC", + "ND", + "OH", + "OK", + "OR", + "PA", + "RI", + "SC", + "SD", + "TN", + "TX", + "UT", + "VT", + "VA", + "WA", + "WV", + "WI", + "WY", +) + +# Some abbreviations are non-standard. +NON_STATE_ABBRS = ( + "AS", + "GU", + "MP", + "PR", + "VI", + r"D\.?C\.?", +) + def states_abbrvs_regex() -> str: - # Some abbreviations are non-standard - _STATE_ABBRS = { - "AL", - "AK", - "AZ", - "AR", - "CA", - "CO", - "CT", - "DE", - "FL", - "GA", - "HI", - "ID", - "IL", - "IN", - "IA", - "KS", - "KY", - "LA", - "ME", - "MD", - "MA", - "MI(?:CH)?\.?", - "MN", - "MS", - "MO", - "MT", - "NE", - "NV", - "NH", - "NJ", - "NM", - "NY|N\.Y\.", - "NC", - "ND", - "OH", - "OK", - "OR", - "PA", - "RI", - "SC", - "SD", - "TN", - "TX", - "UT", - "VT", - "VA", - "WA", - "WV", - "WI", - "WY", - } - _NON_STATE_ABBRS = { - "AS", - "GU", - "MP", - "PR", - "VI", - "D\.?C\.?", - } return ( r"(?:" - + str_list_to_upper_lower_regex(list(_STATE_ABBRS | _NON_STATE_ABBRS)) + + str_list_to_upper_lower_regex(list(STATE_ABBRS + NON_STATE_ABBRS)) + r")(?![A-Za-z])" ) +def state_highway_abbrvs_regex() -> str: + return r"(?:" + "|".join(STATE_ABBRS + NON_STATE_ABBRS) + r")(?![A-Za-z])" + + """ Regexp for matching street name. In example below: @@ -265,7 +271,7 @@ def states_abbrvs_regex() -> str: # Some states name their state-maintained highways by the state abbreviation # and the number. numbered_state_highway = r"""(?:{states}\ \d{{1,4}}(?!\d))""".format( - states=states_abbrvs_regex() + states=state_highway_abbrvs_regex() ) diff --git a/tests/test_parser.py b/tests/test_parser.py index c24e8a4..7cf5f70 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -34,6 +34,17 @@ def test_api_parse_single_street(): assert str(addresses[0].full_address) == "255 SOUTH STREET" +def test_api_parse_single_street_skips_mixed_case_state_highway_false_positive(): + test_address = ( + "Hilmar Cheese Company, Inc.\n" + "Plies: aR 8901 North Lander Avenue\n" + "ANY\n" + "2-CHEESE COMPANY No Hilmar, California 95324" + ) + addresses = parse_single_street(test_address, country="US") + assert str(addresses[0].full_street) == "8901 North Lander Avenue" + + def test_address_class_init(): addr = address.Address( country_id="US", diff --git a/tests/test_parser_us.py b/tests/test_parser_us.py index 0f920b5..f9de30f 100644 --- a/tests/test_parser_us.py +++ b/tests/test_parser_us.py @@ -178,7 +178,9 @@ def test_street_name(input, expected): ("W. STATE ROAD 123", True), ("Alt 123", True), ("Alternate 123", True), + ("NC 54", True), # negative assertions + ("nC 54", False), ], ) def test_numbered_or_typeless_street_name(input, expected):