""" Town-to-county mapping for all 6 New England states. Used to resolve county from service_area text when CheapestOil returns state-level data (NH, RI, VT) without county filtering. For MA/CT/ME, the API has county-level pages so this is only needed as fallback. """ import re import logging # County names for direct mention matching (e.g. "Throughout Rockingham County") _NE_COUNTIES = { "CT": ["Fairfield", "Hartford", "Litchfield", "Middlesex", "New Haven", "New London", "Tolland", "Windham"], "MA": ["Barnstable", "Berkshire", "Bristol", "Dukes", "Essex", "Franklin", "Hampden", "Hampshire", "Middlesex", "Nantucket", "Norfolk", "Plymouth", "Suffolk", "Worcester"], "ME": ["Androscoggin", "Aroostook", "Cumberland", "Franklin", "Hancock", "Kennebec", "Knox", "Lincoln", "Oxford", "Penobscot", "Piscataquis", "Sagadahoc", "Somerset", "Waldo", "Washington", "York"], "NH": ["Belknap", "Carroll", "Cheshire", "Coos", "Grafton", "Hillsborough", "Merrimack", "Rockingham", "Strafford", "Sullivan"], "RI": ["Bristol", "Kent", "Newport", "Providence", "Washington"], "VT": ["Addison", "Bennington", "Caledonia", "Chittenden", "Essex", "Franklin", "Grand Isle", "Lamoille", "Orange", "Orleans", "Rutland", "Washington", "Windham", "Windsor"], } # Town name (lowercase) -> County name, organized by state TOWN_COUNTY_MAP = { "CT": { "andover": "Tolland", "ansonia": "New Haven", "ashford": "Windham", "avon": "Hartford", "barkhamsted": "Litchfield", "beacon falls": "New Haven", "berlin": "Hartford", "bethany": "New Haven", "bethel": "Fairfield", "bethlehem": "Litchfield", "bloomfield": "Hartford", "bolton": "Tolland", "bozrah": "New London", "branford": "New Haven", "bridgeport": "Fairfield", "bridgewater": "Litchfield", "bristol": "Hartford", "brookfield": "Fairfield", "brooklyn": "Windham", "burlington": "Hartford", "canaan": "Litchfield", "canterbury": "Windham", "canton": "Hartford", "chaplin": "Windham", "cheshire": "New Haven", "chester": "Middlesex", "clinton": "Middlesex", "colchester": "New London", "colebrook": "Litchfield", "columbia": "Tolland", "cornwall": "Litchfield", "coventry": "Tolland", "cromwell": "Middlesex", "danbury": "Fairfield", "darien": "Fairfield", "deep river": "Middlesex", "derby": "New Haven", "durham": "Middlesex", "east granby": "Hartford", "east haddam": "Middlesex", "east hampton": "Middlesex", "east hartford": "Hartford", "east haven": "New Haven", "east lyme": "New London", "east windsor": "Hartford", "eastford": "Windham", "easton": "Fairfield", "ellington": "Tolland", "enfield": "Hartford", "essex": "Middlesex", "fairfield": "Fairfield", "farmington": "Hartford", "franklin": "New London", "glastonbury": "Hartford", "goshen": "Litchfield", "granby": "Hartford", "greenwich": "Fairfield", "griswold": "New London", "groton": "New London", "guilford": "New Haven", "haddam": "Middlesex", "hamden": "New Haven", "hampton": "Windham", "hartford": "Hartford", "hartland": "Hartford", "harwinton": "Litchfield", "hebron": "Tolland", "kent": "Litchfield", "killingly": "Windham", "killingworth": "Middlesex", "lebanon": "New London", "ledyard": "New London", "lisbon": "New London", "litchfield": "Litchfield", "lyme": "New London", "madison": "New Haven", "manchester": "Hartford", "mansfield": "Tolland", "marlborough": "Hartford", "meriden": "New Haven", "middlebury": "New Haven", "middlefield": "Middlesex", "middletown": "Middlesex", "milford": "New Haven", "monroe": "Fairfield", "montville": "New London", "morris": "Litchfield", "naugatuck": "New Haven", "new britain": "Hartford", "new canaan": "Fairfield", "new fairfield": "Fairfield", "new hartford": "Litchfield", "new haven": "New Haven", "new london": "New London", "new milford": "Litchfield", "newington": "Hartford", "newtown": "Fairfield", "norfolk": "Litchfield", "north branford": "New Haven", "north canaan": "Litchfield", "north haven": "New Haven", "north stonington": "New London", "norwalk": "Fairfield", "norwich": "New London", "old lyme": "New London", "old saybrook": "Middlesex", "orange": "New Haven", "oxford": "New Haven", "plainfield": "Windham", "plainville": "Hartford", "plymouth": "Litchfield", "pomfret": "Windham", "portland": "Middlesex", "preston": "New London", "prospect": "New Haven", "putnam": "Windham", "redding": "Fairfield", "ridgefield": "Fairfield", "rocky hill": "Hartford", "roxbury": "Litchfield", "salem": "New London", "salisbury": "Litchfield", "scotland": "Windham", "seymour": "New Haven", "sharon": "Litchfield", "shelton": "Fairfield", "sherman": "Fairfield", "simsbury": "Hartford", "somers": "Tolland", "south windsor": "Hartford", "southbury": "New Haven", "southington": "Hartford", "sprague": "New London", "stafford": "Tolland", "stamford": "Fairfield", "sterling": "Windham", "stonington": "New London", "stratford": "Fairfield", "suffield": "Hartford", "thomaston": "Litchfield", "thompson": "Windham", "tolland": "Tolland", "torrington": "Litchfield", "trumbull": "Fairfield", "union": "Tolland", "vernon": "Tolland", "voluntown": "New London", "wallingford": "New Haven", "warren": "Litchfield", "washington": "Litchfield", "waterbury": "New Haven", "waterford": "New London", "watertown": "Litchfield", "west hartford": "Hartford", "west haven": "New Haven", "westbrook": "Middlesex", "weston": "Fairfield", "westport": "Fairfield", "wethersfield": "Hartford", "willington": "Tolland", "wilton": "Fairfield", "winchester": "Litchfield", "windham": "Windham", "windsor": "Hartford", "windsor locks": "Hartford", "wolcott": "New Haven", "woodbridge": "New Haven", "woodbury": "Litchfield", "woodstock": "Windham", }, "MA": { "abington": "Plymouth", "acton": "Middlesex", "acushnet": "Bristol", "adams": "Berkshire", "agawam": "Hampden", "alford": "Berkshire", "amesbury": "Essex", "amherst": "Hampshire", "andover": "Essex", "arlington": "Middlesex", "ashburnham": "Worcester", "ashby": "Middlesex", "ashfield": "Franklin", "ashland": "Middlesex", "athol": "Worcester", "attleboro": "Bristol", "auburn": "Worcester", "avon": "Norfolk", "ayer": "Middlesex", "barnstable": "Barnstable", "barre": "Worcester", "becket": "Berkshire", "bedford": "Middlesex", "belchertown": "Hampshire", "bellingham": "Norfolk", "belmont": "Middlesex", "berkley": "Bristol", "berlin": "Worcester", "bernardston": "Franklin", "beverly": "Essex", "billerica": "Middlesex", "blackstone": "Worcester", "blandford": "Hampden", "bolton": "Worcester", "boston": "Suffolk", "bourne": "Barnstable", "boxborough": "Middlesex", "boxford": "Essex", "boylston": "Worcester", "braintree": "Norfolk", "brewster": "Barnstable", "bridgewater": "Plymouth", "brimfield": "Hampden", "brockton": "Plymouth", "brookfield": "Worcester", "brookline": "Norfolk", "buckland": "Franklin", "burlington": "Middlesex", "cambridge": "Middlesex", "canton": "Norfolk", "carlisle": "Middlesex", "carver": "Plymouth", "charlemont": "Franklin", "charlton": "Worcester", "chatham": "Barnstable", "chelmsford": "Middlesex", "chelsea": "Suffolk", "cheshire": "Berkshire", "chester": "Hampden", "chesterfield": "Hampshire", "chicopee": "Hampden", "chilmark": "Dukes", "clarksburg": "Berkshire", "clinton": "Worcester", "cohasset": "Norfolk", "colrain": "Franklin", "concord": "Middlesex", "conway": "Franklin", "cummington": "Hampshire", "dalton": "Berkshire", "danvers": "Essex", "dartmouth": "Bristol", "dedham": "Norfolk", "deerfield": "Franklin", "dennis": "Barnstable", "dighton": "Bristol", "douglas": "Worcester", "dover": "Norfolk", "dracut": "Middlesex", "dudley": "Worcester", "dunstable": "Middlesex", "duxbury": "Plymouth", "east bridgewater": "Plymouth", "east brookfield": "Worcester", "east longmeadow": "Hampden", "eastham": "Barnstable", "easthampton": "Hampshire", "easton": "Bristol", "edgartown": "Dukes", "egremont": "Berkshire", "erving": "Franklin", "essex": "Essex", "everett": "Middlesex", "fairhaven": "Bristol", "fall river": "Bristol", "falmouth": "Barnstable", "fitchburg": "Worcester", "florida": "Berkshire", "foxborough": "Norfolk", "framingham": "Middlesex", "franklin": "Norfolk", "freetown": "Bristol", "gardner": "Worcester", "georgetown": "Essex", "gill": "Franklin", "gloucester": "Essex", "goshen": "Hampshire", "gosnold": "Dukes", "grafton": "Worcester", "granby": "Hampshire", "granville": "Hampden", "great barrington": "Berkshire", "greenfield": "Franklin", "groton": "Middlesex", "groveland": "Essex", "hadley": "Hampshire", "halifax": "Plymouth", "hamilton": "Essex", "hampden": "Hampden", "hancock": "Berkshire", "hanover": "Plymouth", "hanson": "Plymouth", "hardwick": "Worcester", "harvard": "Worcester", "harwich": "Barnstable", "hatfield": "Hampshire", "haverhill": "Essex", "hawley": "Franklin", "heath": "Franklin", "hingham": "Plymouth", "hinsdale": "Berkshire", "holbrook": "Norfolk", "holden": "Worcester", "holland": "Hampden", "holliston": "Middlesex", "holyoke": "Hampden", "hopedale": "Worcester", "hopkinton": "Middlesex", "hubbardston": "Worcester", "hudson": "Middlesex", "hull": "Plymouth", "huntington": "Hampshire", "ipswich": "Essex", "kingston": "Plymouth", "lakeville": "Plymouth", "lancaster": "Worcester", "lanesborough": "Berkshire", "lawrence": "Essex", "lee": "Berkshire", "leicester": "Worcester", "lenox": "Berkshire", "leominster": "Worcester", "leverett": "Franklin", "lexington": "Middlesex", "leyden": "Franklin", "lincoln": "Middlesex", "littleton": "Middlesex", "longmeadow": "Hampden", "lowell": "Middlesex", "ludlow": "Hampden", "lunenburg": "Worcester", "lynn": "Essex", "lynnfield": "Essex", "malden": "Middlesex", "manchester-by-the-sea": "Essex", "manchester": "Essex", "mansfield": "Bristol", "marblehead": "Essex", "marion": "Plymouth", "marlborough": "Middlesex", "marshfield": "Plymouth", "mashpee": "Barnstable", "mattapoisett": "Plymouth", "maynard": "Middlesex", "medfield": "Norfolk", "medford": "Middlesex", "medway": "Norfolk", "melrose": "Middlesex", "mendon": "Worcester", "merrimac": "Essex", "methuen": "Essex", "middleborough": "Plymouth", "middlefield": "Hampshire", "middleton": "Essex", "milford": "Worcester", "millbury": "Worcester", "millis": "Norfolk", "millville": "Worcester", "milton": "Norfolk", "monroe": "Franklin", "monson": "Hampden", "montague": "Franklin", "monterey": "Berkshire", "montgomery": "Hampden", "mount washington": "Berkshire", "nahant": "Essex", "nantucket": "Nantucket", "natick": "Middlesex", "needham": "Norfolk", "new ashford": "Berkshire", "new bedford": "Bristol", "new braintree": "Worcester", "new marlborough": "Berkshire", "new salem": "Franklin", "newbury": "Essex", "newburyport": "Essex", "newton": "Middlesex", "norfolk": "Norfolk", "north adams": "Berkshire", "north andover": "Essex", "north attleborough": "Bristol", "north brookfield": "Worcester", "north reading": "Middlesex", "northampton": "Hampshire", "northborough": "Worcester", "northbridge": "Worcester", "northfield": "Franklin", "norton": "Bristol", "norwell": "Plymouth", "norwood": "Norfolk", "oak bluffs": "Dukes", "oakham": "Worcester", "orange": "Franklin", "orleans": "Barnstable", "otis": "Berkshire", "oxford": "Worcester", "palmer": "Hampden", "paxton": "Worcester", "peabody": "Essex", "pelham": "Hampshire", "pembroke": "Plymouth", "pepperell": "Middlesex", "peru": "Berkshire", "petersham": "Worcester", "phillipston": "Worcester", "pittsfield": "Berkshire", "plainfield": "Hampshire", "plainville": "Norfolk", "plymouth": "Plymouth", "plympton": "Plymouth", "princeton": "Worcester", "provincetown": "Barnstable", "quincy": "Norfolk", "randolph": "Norfolk", "raynham": "Bristol", "reading": "Middlesex", "rehoboth": "Bristol", "revere": "Suffolk", "richmond": "Berkshire", "rochester": "Plymouth", "rockland": "Plymouth", "rockport": "Essex", "rowe": "Franklin", "rowley": "Essex", "royalston": "Worcester", "russell": "Hampden", "rutland": "Worcester", "salem": "Essex", "salisbury": "Essex", "sandisfield": "Berkshire", "sandwich": "Barnstable", "saugus": "Essex", "savoy": "Berkshire", "scituate": "Plymouth", "seekonk": "Bristol", "sharon": "Norfolk", "sheffield": "Berkshire", "shelburne": "Franklin", "sherborn": "Middlesex", "shirley": "Middlesex", "shrewsbury": "Worcester", "shutesbury": "Franklin", "somerset": "Bristol", "somerville": "Middlesex", "south hadley": "Hampshire", "southampton": "Hampshire", "southborough": "Worcester", "southbridge": "Worcester", "southwick": "Hampden", "spencer": "Worcester", "springfield": "Hampden", "sterling": "Worcester", "stockbridge": "Berkshire", "stoneham": "Middlesex", "stoughton": "Norfolk", "stow": "Middlesex", "sturbridge": "Worcester", "sudbury": "Middlesex", "sunderland": "Franklin", "sutton": "Worcester", "swampscott": "Essex", "swansea": "Bristol", "taunton": "Bristol", "templeton": "Worcester", "tewksbury": "Middlesex", "tisbury": "Dukes", "tolland": "Hampden", "topsfield": "Essex", "townsend": "Middlesex", "truro": "Barnstable", "tyngsborough": "Middlesex", "tyringham": "Berkshire", "upton": "Worcester", "uxbridge": "Worcester", "wakefield": "Middlesex", "wales": "Hampden", "walpole": "Norfolk", "waltham": "Middlesex", "ware": "Hampshire", "wareham": "Plymouth", "warren": "Worcester", "warwick": "Franklin", "washington": "Berkshire", "watertown": "Middlesex", "wayland": "Middlesex", "webster": "Worcester", "wellesley": "Norfolk", "wellfleet": "Barnstable", "wendell": "Franklin", "wenham": "Essex", "west boylston": "Worcester", "west bridgewater": "Plymouth", "west brookfield": "Worcester", "west newbury": "Essex", "west springfield": "Hampden", "west stockbridge": "Berkshire", "west tisbury": "Dukes", "westborough": "Worcester", "westfield": "Hampden", "westford": "Middlesex", "westhampton": "Hampshire", "westminster": "Worcester", "weston": "Middlesex", "westport": "Bristol", "westwood": "Norfolk", "weymouth": "Norfolk", "whately": "Franklin", "whitman": "Plymouth", "wilbraham": "Hampden", "williamsburg": "Hampshire", "williamstown": "Berkshire", "wilmington": "Middlesex", "winchendon": "Worcester", "winchester": "Middlesex", "windsor": "Berkshire", "winthrop": "Suffolk", "woburn": "Middlesex", "worcester": "Worcester", "worthington": "Hampshire", "wrentham": "Norfolk", "yarmouth": "Barnstable", }, "ME": { "auburn": "Androscoggin", "durham": "Androscoggin", "greene": "Androscoggin", "leeds": "Androscoggin", "lewiston": "Androscoggin", "lisbon": "Androscoggin", "livermore": "Androscoggin", "livermore falls": "Androscoggin", "mechanic falls": "Androscoggin", "minot": "Androscoggin", "poland": "Androscoggin", "sabattus": "Androscoggin", "turner": "Androscoggin", "wales": "Androscoggin", "allagash": "Aroostook", "amity": "Aroostook", "ashland": "Aroostook", "bancroft": "Aroostook", "blaine": "Aroostook", "bridgewater": "Aroostook", "caribou": "Aroostook", "castle hill": "Aroostook", "caswell": "Aroostook", "chapman": "Aroostook", "connor": "Aroostook", "crystal": "Aroostook", "dyer brook": "Aroostook", "eagle lake": "Aroostook", "easton": "Aroostook", "fort fairfield": "Aroostook", "fort kent": "Aroostook", "frenchville": "Aroostook", "grand isle": "Aroostook", "hamlin": "Aroostook", "haynesville": "Aroostook", "hersey": "Aroostook", "hodgdon": "Aroostook", "houlton": "Aroostook", "island falls": "Aroostook", "limestone": "Aroostook", "linneus": "Aroostook", "littleton": "Aroostook", "ludlow": "Aroostook", "madawaska": "Aroostook", "mapleton": "Aroostook", "mars hill": "Aroostook", "masardis": "Aroostook", "merrill": "Aroostook", "monticello": "Aroostook", "new canada": "Aroostook", "new limerick": "Aroostook", "new sweden": "Aroostook", "oakfield": "Aroostook", "orient": "Aroostook", "perham": "Aroostook", "portage lake": "Aroostook", "presque isle": "Aroostook", "saint agatha": "Aroostook", "saint francis": "Aroostook", "sherman": "Aroostook", "smyrna": "Aroostook", "stockholm": "Aroostook", "van buren": "Aroostook", "wade": "Aroostook", "wallagrass": "Aroostook", "washburn": "Aroostook", "westfield": "Aroostook", "weston": "Aroostook", "woodland": "Aroostook", "baldwin": "Cumberland", "bridgton": "Cumberland", "brunswick": "Cumberland", "cape elizabeth": "Cumberland", "casco": "Cumberland", "chebeague island": "Cumberland", "cumberland": "Cumberland", "falmouth": "Cumberland", "freeport": "Cumberland", "frye island": "Cumberland", "gorham": "Cumberland", "gray": "Cumberland", "harpswell": "Cumberland", "harrison": "Cumberland", "long island": "Cumberland", "naples": "Cumberland", "new gloucester": "Cumberland", "north yarmouth": "Cumberland", "portland": "Cumberland", "pownal": "Cumberland", "raymond": "Cumberland", "scarborough": "Cumberland", "sebago": "Cumberland", "south portland": "Cumberland", "standish": "Cumberland", "westbrook": "Cumberland", "windham": "Cumberland", "yarmouth": "Cumberland", "avon": "Franklin", "carrabassett valley": "Franklin", "carthage": "Franklin", "chesterville": "Franklin", "eustis": "Franklin", "farmington": "Franklin", "industry": "Franklin", "jay": "Franklin", "kingfield": "Franklin", "new sharon": "Franklin", "new vineyard": "Franklin", "phillips": "Franklin", "rangeley": "Franklin", "strong": "Franklin", "temple": "Franklin", "weld": "Franklin", "wilton": "Franklin", "amherst": "Hancock", "aurora": "Hancock", "bar harbor": "Hancock", "blue hill": "Hancock", "brooklin": "Hancock", "brooksville": "Hancock", "bucksport": "Hancock", "castine": "Hancock", "cranberry isles": "Hancock", "dedham": "Hancock", "deer isle": "Hancock", "eastbrook": "Hancock", "ellsworth": "Hancock", "franklin": "Hancock", "frenchboro": "Hancock", "gouldsboro": "Hancock", "hancock": "Hancock", "lamoine": "Hancock", "mariaville": "Hancock", "mount desert": "Hancock", "orland": "Hancock", "otis": "Hancock", "penobscot": "Hancock", "sedgwick": "Hancock", "sorrento": "Hancock", "southwest harbor": "Hancock", "stonington": "Hancock", "sullivan": "Hancock", "surry": "Hancock", "swans island": "Hancock", "tremont": "Hancock", "trenton": "Hancock", "verona island": "Hancock", "waltham": "Hancock", "winter harbor": "Hancock", "albion": "Kennebec", "augusta": "Kennebec", "belgrade": "Kennebec", "benton": "Kennebec", "chelsea": "Kennebec", "china": "Kennebec", "clinton": "Kennebec", "farmingdale": "Kennebec", "fayette": "Kennebec", "gardiner": "Kennebec", "hallowell": "Kennebec", "litchfield": "Kennebec", "manchester": "Kennebec", "monmouth": "Kennebec", "mount vernon": "Kennebec", "oakland": "Kennebec", "pittston": "Kennebec", "randolph": "Kennebec", "readfield": "Kennebec", "rome": "Kennebec", "sidney": "Kennebec", "vassalboro": "Kennebec", "vienna": "Kennebec", "waterville": "Kennebec", "wayne": "Kennebec", "west gardiner": "Kennebec", "windsor": "Kennebec", "winslow": "Kennebec", "winthrop": "Kennebec", "appleton": "Knox", "camden": "Knox", "cushing": "Knox", "friendship": "Knox", "hope": "Knox", "isle au haut": "Knox", "north haven": "Knox", "owls head": "Knox", "rockland": "Knox", "rockport": "Knox", "saint george": "Knox", "south thomaston": "Knox", "thomaston": "Knox", "union": "Knox", "vinalhaven": "Knox", "warren": "Knox", "washington": "Knox", "alna": "Lincoln", "boothbay": "Lincoln", "boothbay harbor": "Lincoln", "bremen": "Lincoln", "bristol": "Lincoln", "damariscotta": "Lincoln", "dresden": "Lincoln", "edgecomb": "Lincoln", "jefferson": "Lincoln", "newcastle": "Lincoln", "nobleboro": "Lincoln", "somerville": "Lincoln", "south bristol": "Lincoln", "southport": "Lincoln", "waldoboro": "Lincoln", "westport island": "Lincoln", "whitefield": "Lincoln", "wiscasset": "Lincoln", "albany": "Oxford", "andover": "Oxford", "bethel": "Oxford", "brownfield": "Oxford", "buckfield": "Oxford", "byron": "Oxford", "canton": "Oxford", "denmark": "Oxford", "dixfield": "Oxford", "fryeburg": "Oxford", "gilead": "Oxford", "greenwood": "Oxford", "hanover": "Oxford", "hartford": "Oxford", "hebron": "Oxford", "hiram": "Oxford", "lovell": "Oxford", "mexico": "Oxford", "newry": "Oxford", "norway": "Oxford", "oxford": "Oxford", "paris": "Oxford", "peru": "Oxford", "porter": "Oxford", "roxbury": "Oxford", "rumford": "Oxford", "stoneham": "Oxford", "stow": "Oxford", "sumner": "Oxford", "sweden": "Oxford", "upton": "Oxford", "waterford": "Oxford", "west paris": "Oxford", "woodstock": "Oxford", "milton": "Oxford", "alton": "Penobscot", "bangor": "Penobscot", "bradford": "Penobscot", "bradley": "Penobscot", "brewer": "Penobscot", "burlington": "Penobscot", "carmel": "Penobscot", "charleston": "Penobscot", "chester": "Penobscot", "clifton": "Penobscot", "corinna": "Penobscot", "corinth": "Penobscot", "dexter": "Penobscot", "dixmont": "Penobscot", "east millinocket": "Penobscot", "eddington": "Penobscot", "edinburg": "Penobscot", "enfield": "Penobscot", "etna": "Penobscot", "exeter": "Penobscot", "garland": "Penobscot", "glenburn": "Penobscot", "greenbush": "Penobscot", "greenfield": "Penobscot", "hampden": "Penobscot", "holden": "Penobscot", "howland": "Penobscot", "hudson": "Penobscot", "kenduskeag": "Penobscot", "lagrange": "Penobscot", "lee": "Penobscot", "levant": "Penobscot", "lincoln": "Penobscot", "lowell": "Penobscot", "mattawamkeag": "Penobscot", "maxfield": "Penobscot", "medway": "Penobscot", "milford": "Penobscot", "millinocket": "Penobscot", "newburgh": "Penobscot", "newport": "Penobscot", "old town": "Penobscot", "orono": "Penobscot", "orrington": "Penobscot", "passadumkeag": "Penobscot", "patten": "Penobscot", "plymouth": "Penobscot", "prentiss": "Penobscot", "stetson": "Penobscot", "springfield": "Penobscot", "stacyville": "Penobscot", "veazie": "Penobscot", "winn": "Penobscot", "woodville": "Penobscot", "mount chase": "Penobscot", "abbot": "Piscataquis", "atkinson": "Piscataquis", "beaver cove": "Piscataquis", "bowerbank": "Piscataquis", "brownville": "Piscataquis", "dover-foxcroft": "Piscataquis", "greenville": "Piscataquis", "guilford": "Piscataquis", "medford": "Piscataquis", "milo": "Piscataquis", "monson": "Piscataquis", "parkman": "Piscataquis", "sangerville": "Piscataquis", "sebec": "Piscataquis", "shirley": "Piscataquis", "wellington": "Piscataquis", "willimantic": "Piscataquis", "arrowsic": "Sagadahoc", "bath": "Sagadahoc", "bowdoin": "Sagadahoc", "bowdoinham": "Sagadahoc", "georgetown": "Sagadahoc", "phippsburg": "Sagadahoc", "richmond": "Sagadahoc", "topsham": "Sagadahoc", "west bath": "Sagadahoc", "woolwich": "Sagadahoc", "anson": "Somerset", "athens": "Somerset", "bingham": "Somerset", "cambridge": "Somerset", "canaan": "Somerset", "caratunk": "Somerset", "cornville": "Somerset", "detroit": "Somerset", "embden": "Somerset", "fairfield": "Somerset", "harmony": "Somerset", "hartland": "Somerset", "jackman": "Somerset", "madison": "Somerset", "mercer": "Somerset", "moscow": "Somerset", "new portland": "Somerset", "norridgewock": "Somerset", "palmyra": "Somerset", "pittsfield": "Somerset", "ripley": "Somerset", "saint albans": "Somerset", "skowhegan": "Somerset", "smithfield": "Somerset", "solon": "Somerset", "starks": "Somerset", "belfast": "Waldo", "belmont": "Waldo", "brooks": "Waldo", "burnham": "Waldo", "frankfort": "Waldo", "freedom": "Waldo", "islesboro": "Waldo", "jackson": "Waldo", "knox": "Waldo", "liberty": "Waldo", "lincolnville": "Waldo", "monroe": "Waldo", "montville": "Waldo", "morrill": "Waldo", "northport": "Waldo", "palermo": "Waldo", "prospect": "Waldo", "searsmont": "Waldo", "searsport": "Waldo", "stockton springs": "Waldo", "swanville": "Waldo", "thorndike": "Waldo", "troy": "Waldo", "unity": "Waldo", "waldo": "Waldo", "winterport": "Waldo", "addison": "Washington", "alexander": "Washington", "baileyville": "Washington", "beals": "Washington", "beddington": "Washington", "calais": "Washington", "centerville": "Washington", "charlotte": "Washington", "cherryfield": "Washington", "columbia": "Washington", "columbia falls": "Washington", "cooper": "Washington", "crawford": "Washington", "cutler": "Washington", "danforth": "Washington", "deblois": "Washington", "dennysville": "Washington", "east machias": "Washington", "eastport": "Washington", "harrington": "Washington", "jonesboro": "Washington", "jonesport": "Washington", "lubec": "Washington", "machias": "Washington", "machiasport": "Washington", "marion": "Washington", "marshfield": "Washington", "meddybemps": "Washington", "milbridge": "Washington", "northfield": "Washington", "pembroke": "Washington", "perry": "Washington", "princeton": "Washington", "robbinston": "Washington", "roque bluffs": "Washington", "steuben": "Washington", "talmadge": "Washington", "topsfield": "Washington", "vanceboro": "Washington", "waite": "Washington", "wesley": "Washington", "whiting": "Washington", "whitneyville": "Washington", "acton": "York", "alfred": "York", "arundel": "York", "berwick": "York", "biddeford": "York", "buxton": "York", "cornish": "York", "dayton": "York", "eliot": "York", "hollis": "York", "kennebunk": "York", "kennebunkport": "York", "kittery": "York", "lebanon": "York", "limerick": "York", "limington": "York", "lyman": "York", "newfield": "York", "north berwick": "York", "ogunquit": "York", "old orchard beach": "York", "parsonsfield": "York", "saco": "York", "sanford": "York", "shapleigh": "York", "south berwick": "York", "waterboro": "York", "wells": "York", "york": "York", }, "NH": { "acworth": "Sullivan", "albany": "Carroll", "alexandria": "Grafton", "allenstown": "Merrimack", "alstead": "Cheshire", "alton": "Belknap", "amherst": "Hillsborough", "andover": "Merrimack", "antrim": "Hillsborough", "ashland": "Grafton", "atkinson": "Rockingham", "auburn": "Rockingham", "barnstead": "Belknap", "barrington": "Strafford", "bartlett": "Carroll", "bath": "Grafton", "bedford": "Hillsborough", "belmont": "Belknap", "bennington": "Hillsborough", "benton": "Grafton", "berlin": "Coos", "bethlehem": "Grafton", "boscawen": "Merrimack", "bow": "Merrimack", "bradford": "Merrimack", "brentwood": "Rockingham", "bridgewater": "Grafton", "bristol": "Grafton", "brookfield": "Carroll", "brookline": "Hillsborough", "campton": "Grafton", "canaan": "Grafton", "candia": "Rockingham", "canterbury": "Merrimack", "carroll": "Coos", "center harbor": "Belknap", "charlestown": "Sullivan", "chatham": "Carroll", "chester": "Rockingham", "chesterfield": "Cheshire", "chichester": "Merrimack", "claremont": "Sullivan", "clarksville": "Coos", "colebrook": "Coos", "columbia": "Coos", "concord": "Merrimack", "conway": "Carroll", "cornish": "Sullivan", "croydon": "Sullivan", "dalton": "Coos", "danbury": "Merrimack", "danville": "Rockingham", "deerfield": "Rockingham", "deering": "Hillsborough", "derry": "Rockingham", "dorchester": "Grafton", "dover": "Strafford", "dublin": "Cheshire", "dummer": "Coos", "dunbarton": "Merrimack", "durham": "Strafford", "east kingston": "Rockingham", "easton": "Grafton", "eaton": "Carroll", "effingham": "Carroll", "ellsworth": "Grafton", "enfield": "Grafton", "epping": "Rockingham", "epsom": "Merrimack", "errol": "Coos", "exeter": "Rockingham", "farmington": "Strafford", "fitzwilliam": "Cheshire", "francestown": "Hillsborough", "franconia": "Grafton", "franklin": "Merrimack", "freedom": "Carroll", "fremont": "Rockingham", "gilford": "Belknap", "gilmanton": "Belknap", "gilsum": "Cheshire", "goffstown": "Hillsborough", "gorham": "Coos", "goshen": "Sullivan", "grafton": "Grafton", "grantham": "Sullivan", "greenfield": "Hillsborough", "greenland": "Rockingham", "greenville": "Hillsborough", "groton": "Grafton", "hampstead": "Rockingham", "hampton": "Rockingham", "hampton falls": "Rockingham", "hancock": "Hillsborough", "hanover": "Grafton", "harrisville": "Cheshire", "hart's location": "Carroll", "haverhill": "Grafton", "hebron": "Grafton", "henniker": "Merrimack", "hill": "Merrimack", "hillsborough": "Hillsborough", "hinsdale": "Cheshire", "holderness": "Grafton", "hollis": "Hillsborough", "hooksett": "Merrimack", "hopkinton": "Merrimack", "hudson": "Hillsborough", "jackson": "Carroll", "jaffrey": "Cheshire", "jefferson": "Coos", "keene": "Cheshire", "kensington": "Rockingham", "kingston": "Rockingham", "laconia": "Belknap", "lancaster": "Coos", "landaff": "Grafton", "langdon": "Sullivan", "lee": "Strafford", "lempster": "Sullivan", "lincoln": "Grafton", "lisbon": "Grafton", "litchfield": "Hillsborough", "littleton": "Grafton", "londonderry": "Rockingham", "loudon": "Merrimack", "lyme": "Grafton", "lyndeborough": "Hillsborough", "madbury": "Strafford", "madison": "Carroll", "manchester": "Hillsborough", "marlborough": "Cheshire", "marlow": "Cheshire", "mason": "Hillsborough", "meredith": "Belknap", "merrimack": "Hillsborough", "middleton": "Strafford", "milan": "Coos", "milford": "Hillsborough", "millsfield": "Coos", "milton": "Strafford", "monroe": "Grafton", "mont vernon": "Hillsborough", "moultonborough": "Carroll", "nashua": "Hillsborough", "nelson": "Cheshire", "new boston": "Hillsborough", "new castle": "Rockingham", "new durham": "Strafford", "new hampton": "Belknap", "new ipswich": "Hillsborough", "new london": "Merrimack", "newbury": "Merrimack", "newfields": "Rockingham", "newington": "Rockingham", "newmarket": "Rockingham", "newport": "Sullivan", "newton": "Rockingham", "north hampton": "Rockingham", "northfield": "Merrimack", "northumberland": "Coos", "northwood": "Rockingham", "nottingham": "Rockingham", "orange": "Grafton", "orford": "Grafton", "ossipee": "Carroll", "pelham": "Hillsborough", "pembroke": "Merrimack", "peterborough": "Hillsborough", "piermont": "Grafton", "pittsburg": "Coos", "pittsfield": "Merrimack", "plainfield": "Sullivan", "plaistow": "Rockingham", "plymouth": "Grafton", "portsmouth": "Rockingham", "randolph": "Coos", "raymond": "Rockingham", "richmond": "Cheshire", "rindge": "Cheshire", "rochester": "Strafford", "rollinsford": "Strafford", "roxbury": "Cheshire", "rumney": "Grafton", "rye": "Rockingham", "salem": "Rockingham", "salisbury": "Merrimack", "sanbornton": "Belknap", "sandown": "Rockingham", "sandwich": "Carroll", "seabrook": "Rockingham", "sharon": "Hillsborough", "shelburne": "Coos", "somersworth": "Strafford", "south hampton": "Rockingham", "springfield": "Sullivan", "stark": "Coos", "stewartstown": "Coos", "stoddard": "Cheshire", "strafford": "Strafford", "stratford": "Coos", "stratham": "Rockingham", "sugar hill": "Grafton", "sunapee": "Sullivan", "surry": "Cheshire", "sutton": "Merrimack", "swanzey": "Cheshire", "tamworth": "Carroll", "temple": "Hillsborough", "thornton": "Grafton", "tilton": "Belknap", "troy": "Cheshire", "tuftonboro": "Carroll", "unity": "Sullivan", "wakefield": "Carroll", "walpole": "Cheshire", "warner": "Merrimack", "warren": "Grafton", "washington": "Sullivan", "waterville valley": "Grafton", "weare": "Hillsborough", "webster": "Merrimack", "wentworth": "Grafton", "westmoreland": "Cheshire", "whitefield": "Coos", "wilmot": "Merrimack", "wilton": "Hillsborough", "winchester": "Cheshire", "windham": "Rockingham", "windsor": "Hillsborough", "wolfeboro": "Carroll", "woodstock": "Grafton", }, "RI": { "barrington": "Bristol", "bristol": "Bristol", "warren": "Bristol", "coventry": "Kent", "east greenwich": "Kent", "warwick": "Kent", "west greenwich": "Kent", "west warwick": "Kent", "jamestown": "Newport", "little compton": "Newport", "middletown": "Newport", "newport": "Newport", "portsmouth": "Newport", "tiverton": "Newport", "burrillville": "Providence", "central falls": "Providence", "cranston": "Providence", "cumberland": "Providence", "east providence": "Providence", "foster": "Providence", "glocester": "Providence", "johnston": "Providence", "lincoln": "Providence", "north providence": "Providence", "north smithfield": "Providence", "pawtucket": "Providence", "providence": "Providence", "scituate": "Providence", "smithfield": "Providence", "woonsocket": "Providence", "charlestown": "Washington", "exeter": "Washington", "hopkinton": "Washington", "narragansett": "Washington", "new shoreham": "Washington", "north kingstown": "Washington", "richmond": "Washington", "south kingstown": "Washington", "westerly": "Washington", }, "VT": { "addison": "Addison", "bridport": "Addison", "bristol": "Addison", "cornwall": "Addison", "ferrisburgh": "Addison", "goshen": "Addison", "granville": "Addison", "hancock": "Addison", "leicester": "Addison", "lincoln": "Addison", "middlebury": "Addison", "monkton": "Addison", "new haven": "Addison", "orwell": "Addison", "panton": "Addison", "ripton": "Addison", "salisbury": "Addison", "shoreham": "Addison", "starksboro": "Addison", "vergennes": "Addison", "waltham": "Addison", "weybridge": "Addison", "whiting": "Addison", "arlington": "Bennington", "bennington": "Bennington", "dorset": "Bennington", "glastenbury": "Bennington", "landgrove": "Bennington", "manchester": "Bennington", "peru": "Bennington", "pownal": "Bennington", "readsboro": "Bennington", "rupert": "Bennington", "sandgate": "Bennington", "searsburg": "Bennington", "shaftsbury": "Bennington", "stamford": "Bennington", "sunderland": "Bennington", "winhall": "Bennington", "woodford": "Bennington", "barnet": "Caledonia", "burke": "Caledonia", "danville": "Caledonia", "groton": "Caledonia", "hardwick": "Caledonia", "kirby": "Caledonia", "lyndon": "Caledonia", "newark": "Caledonia", "peacham": "Caledonia", "ryegate": "Caledonia", "sheffield": "Caledonia", "st. johnsbury": "Caledonia", "st johnsbury": "Caledonia", "stannard": "Caledonia", "sutton": "Caledonia", "walden": "Caledonia", "waterford": "Caledonia", "wheelock": "Caledonia", "bolton": "Chittenden", "burlington": "Chittenden", "charlotte": "Chittenden", "colchester": "Chittenden", "essex": "Chittenden", "essex junction": "Chittenden", "hinesburg": "Chittenden", "huntington": "Chittenden", "jericho": "Chittenden", "milton": "Chittenden", "richmond": "Chittenden", "shelburne": "Chittenden", "south burlington": "Chittenden", "underhill": "Chittenden", "westford": "Chittenden", "williston": "Chittenden", "winooski": "Chittenden", "averill": "Essex", "bloomfield": "Essex", "brighton": "Essex", "brunswick": "Essex", "canaan": "Essex", "concord": "Essex", "east haven": "Essex", "ferdinand": "Essex", "granby": "Essex", "guildhall": "Essex", "lemington": "Essex", "lunenburg": "Essex", "maidstone": "Essex", "norton": "Essex", "victory": "Essex", "bakersfield": "Franklin", "berkshire": "Franklin", "enosburg": "Franklin", "enosburg falls": "Franklin", "fairfax": "Franklin", "fairfield": "Franklin", "fletcher": "Franklin", "franklin": "Franklin", "georgia": "Franklin", "highgate": "Franklin", "montgomery": "Franklin", "richford": "Franklin", "sheldon": "Franklin", "st. albans": "Franklin", "st albans": "Franklin", "swanton": "Franklin", "alburgh": "Grand Isle", "grand isle": "Grand Isle", "isle la motte": "Grand Isle", "north hero": "Grand Isle", "south hero": "Grand Isle", "belvidere": "Lamoille", "cambridge": "Lamoille", "eden": "Lamoille", "elmore": "Lamoille", "hyde park": "Lamoille", "johnson": "Lamoille", "morristown": "Lamoille", "morrisville": "Lamoille", "stowe": "Lamoille", "waterville": "Lamoille", "wolcott": "Lamoille", "bradford": "Orange", "braintree": "Orange", "brookfield": "Orange", "chelsea": "Orange", "corinth": "Orange", "fairlee": "Orange", "newbury": "Orange", "orange": "Orange", "randolph": "Orange", "strafford": "Orange", "thetford": "Orange", "topsham": "Orange", "tunbridge": "Orange", "vershire": "Orange", "washington": "Orange", "west fairlee": "Orange", "williamstown": "Orange", "albany": "Orleans", "barton": "Orleans", "brownington": "Orleans", "charleston": "Orleans", "coventry": "Orleans", "craftsbury": "Orleans", "derby": "Orleans", "glover": "Orleans", "greensboro": "Orleans", "holland": "Orleans", "irasburgh": "Orleans", "jay": "Orleans", "lowell": "Orleans", "morgan": "Orleans", "newport": "Orleans", "troy": "Orleans", "westfield": "Orleans", "westmore": "Orleans", "benson": "Rutland", "brandon": "Rutland", "castleton": "Rutland", "chittenden": "Rutland", "clarendon": "Rutland", "danby": "Rutland", "fair haven": "Rutland", "hubbardton": "Rutland", "ira": "Rutland", "killington": "Rutland", "mendon": "Rutland", "middletown springs": "Rutland", "mount holly": "Rutland", "mount tabor": "Rutland", "pawlet": "Rutland", "pittsfield": "Rutland", "pittsford": "Rutland", "poultney": "Rutland", "proctor": "Rutland", "rutland": "Rutland", "shrewsbury": "Rutland", "sudbury": "Rutland", "tinmouth": "Rutland", "wallingford": "Rutland", "west haven": "Rutland", "west rutland": "Rutland", "barre": "Washington", "berlin": "Washington", "cabot": "Washington", "calais": "Washington", "duxbury": "Washington", "east montpelier": "Washington", "fayston": "Washington", "marshfield": "Washington", "middlesex": "Washington", "montpelier": "Washington", "moretown": "Washington", "northfield": "Washington", "plainfield": "Washington", "roxbury": "Washington", "waitsfield": "Washington", "warren": "Washington", "waterbury": "Washington", "woodbury": "Washington", "worcester": "Washington", "athens": "Windham", "brattleboro": "Windham", "brookline": "Windham", "dover": "Windham", "dummerston": "Windham", "grafton": "Windham", "guilford": "Windham", "halifax": "Windham", "jamaica": "Windham", "londonderry": "Windham", "marlboro": "Windham", "newfane": "Windham", "putney": "Windham", "rockingham": "Windham", "somerset": "Windham", "stratton": "Windham", "townshend": "Windham", "vernon": "Windham", "wardsboro": "Windham", "westminster": "Windham", "whitingham": "Windham", "wilmington": "Windham", "windham": "Windham", "andover": "Windsor", "baltimore": "Windsor", "barnard": "Windsor", "bethel": "Windsor", "bridgewater": "Windsor", "cavendish": "Windsor", "chester": "Windsor", "hartford": "Windsor", "hartland": "Windsor", "ludlow": "Windsor", "norwich": "Windsor", "plymouth": "Windsor", "pomfret": "Windsor", "reading": "Windsor", "rochester": "Windsor", "royalton": "Windsor", "sharon": "Windsor", "springfield": "Windsor", "stockbridge": "Windsor", "weathersfield": "Windsor", "weston": "Windsor", "west windsor": "Windsor", "windsor": "Windsor", "woodstock": "Windsor", }, } def resolve_county_from_service_area(service_area: str, state_abbr: str) -> str | None: """ Try to resolve a county name from a service area text string. Strategy: 1. Check for direct county name mentions (e.g. "Throughout Rockingham County") 2. Tokenize and check each token against TOWN_COUNTY_MAP Args: service_area: Free-text service area from CheapestOil state_abbr: Two-letter state code Returns: County name string or None if no match found. """ if not service_area or state_abbr not in TOWN_COUNTY_MAP: return None text = service_area.strip() text_lower = text.lower() # 1. Check for direct county name mentions counties = _NE_COUNTIES.get(state_abbr, []) for county in counties: if county.lower() in text_lower: return county # 2. Tokenize and check against town map town_map = TOWN_COUNTY_MAP[state_abbr] # Split on common delimiters: commas, "and", semicolons, slashes tokens = re.split(r'[,;/&]+|\band\b', text_lower) for token in tokens: token = token.strip().rstrip('.') if not token: continue # Direct match if token in town_map: return town_map[token] # Try without common prefixes/suffixes like "greater", "area", "surrounding" for prefix in ("greater ", "the ", "town of ", "city of "): if token.startswith(prefix): cleaned = token[len(prefix):] if cleaned in town_map: return town_map[cleaned] return None