mainegeo.townships

Town and township name standardization and parsing utilities.

This module provides functions for parsing and normalizing township names and looking up their canonical names.

All functions in this module are intended to be run on a string containing a single town or township, unless specifically indicated otherwise. For help parsing multi-town election reporting units into single town strings, see mainegeo.elections.

  1"""Town and township name standardization and parsing utilities.
  2
  3This module provides functions for parsing and normalizing township names
  4and looking up their canonical names.
  5
  6All functions in this module are intended to be run on a string containing a single 
  7town or township, unless specifically indicated otherwise. For help parsing multi-town 
  8election reporting units into single town strings, see `mainegeo.elections`.
  9"""
 10
 11__docformat__ = 'google'
 12
 13__all__ = [
 14    'is_unnamed_township',
 15    'clean_code',
 16    'clean_codes',
 17    'has_alias',
 18    'extract_alias',
 19    'clean_township',
 20    'strip_region',
 21    'strip_suffix',
 22    'toggle_suffix',
 23    'normalize_suffix',
 24    'strip_town',
 25    'clean_town'
 26]
 27
 28from re import IGNORECASE
 29from mainegeo._vendor import (
 30    replace_all,
 31    squish,
 32    match_case,
 33    normalize_whitespace,
 34    chain_operations
 35)
 36from mainegeo.entities import TownType
 37from mainegeo.patterns import (
 38    UNNAMED_PATTERN, 
 39    UNNAMED_ELEMENTS_PATTERN,
 40    CLEAN_TOWNSHIP_PATTERN,
 41    NON_ALIAS_PATTERN,
 42    GNIS_PATTERN,
 43    ABBREVIATIONS,
 44    SUFFIX_REPLACEMENTS,
 45    SUFFIX_PATTERN,
 46    LAST_REGION_PATTERN,
 47    VALID_AMPERSANDS_PATTERN,
 48    INVALID_PUNCTUATION_PATTERN,
 49    CONTAINS_JUNIOR_SUFFIX_PATTERN,
 50    ENDSWITH_JUNIOR_SUFFIX_PATTERN
 51)
 52
 53def is_unnamed_township(town: str) -> bool:
 54    """
 55    Check if a string contains an unnamed township.
 56
 57    Args:
 58        town: A single town or township
 59        
 60    Returns:
 61        True if input contains an unnamed township, else False
 62        
 63    Examples:
 64        >>> is_unnamed_township('T5 R7')
 65        True
 66        
 67        >>> is_unnamed_township('CROSS LAKE TWP (T17 R5)')
 68        True
 69        
 70        >>> is_unnamed_township('CROSS LAKE TWP')
 71        False
 72    """
 73    return UNNAMED_PATTERN.search(town) is not None
 74
 75def clean_code(town: str) -> str:
 76    """
 77    Normalize punctuation and spacing of township code and drop text that is not part of the township code.
 78
 79    Args:
 80        town: A single town or township
 81
 82    Returns:
 83        Normalized township string, or unmodified string if input does not contain township
 84        
 85    Examples:
 86        >>> clean_code('T4/R3 TWP')
 87        'T4 R3'
 88        
 89        >>> clean_code('T10SD')
 90        'T10 SD'
 91        
 92        >>> clean_code('FLETCHERS LANDING TWP (T8 SD)')
 93        'T8 SD'
 94    """
 95    if is_unnamed_township(town) is False:
 96        return town
 97    else:
 98        elements = UNNAMED_ELEMENTS_PATTERN.findall(town)
 99        formatted_elements = [CLEAN_TOWNSHIP_PATTERN.sub('', e) for e in elements]
100        return ' '.join(formatted_elements)
101
102def clean_codes(towns: str) -> str:
103    """
104    Normalize punctation and spacing of township codes in-place.
105
106    Args:
107        towns: String with one or more towns or townships
108
109    Returns:
110        Input string with punctuation and spacing normalized for all township codes
111        
112    Examples:
113        >>> clean_codes('ASHLAND -- T12/R13, T9/R8')
114        'ASHLAND -- T12 R13, T9 R8'
115        
116        >>> clean_codes('T4/R3 TWP')
117        'T4 R3 TWP'
118        
119        >>> clean_codes('BARNARD TWP/EBEEMEE TWP (T5-R9 NWP)/T4R9 NWP TWP')
120        'BARNARD TWP/EBEEMEE TWP (T5 R9 NWP)/T4 R9 NWP TWP'
121    """
122    townships = UNNAMED_PATTERN.findall(towns)
123    cleaned = list(map(clean_code, townships))
124    return replace_all(dict(zip(townships, cleaned)), towns)
125
126def has_alias(town: str) -> str:
127    """
128    Check if input has both an unnamed township and a township alias.
129
130    Args:
131        town: A single town or township
132
133    Returns:
134        True if town string contains a township code and alias, else False
135
136    Examples:
137        >>> has_alias('CROSS LAKE TWP (T17 R5)')
138        True
139        
140        >>> has_alias('EBEEMEE TWP')
141        False
142        
143        >>> has_alias('PRENTISS TWP T7 R3 NBPP')
144        True
145        
146        >>> has_alias('T7 R3 NBPP TWP')
147        False
148    """
149    if is_unnamed_township(town) is False:
150        return False
151    else:
152        return len(NON_ALIAS_PATTERN.sub('', town).strip()) > 0
153
154def extract_alias(town: str) -> str:
155    """
156    Extract the township alias from a string that contains both an alias and a code.
157
158    Args:
159        town: A single town or township
160
161    Returns:
162        Input string with township code removed.
163
164    Examples:
165        >>> extract_alias('CROSS LAKE TWP (T17 R5)')
166        'CROSS LAKE TWP'
167        
168        >>> extract_alias('T3 Indian Purchase Twp')
169        'Indian Purchase Twp'
170        
171        >>> extract_alias('Rockwood Strip (T1 R1) Twp')
172        'Rockwood Strip Twp'
173        
174        >>> extract_alias('T7 R3 NBPP (PRENTISS TWP)')
175        'PRENTISS TWP'
176    """
177    if has_alias(town):
178        return squish(NON_ALIAS_PATTERN.sub('', town))    
179    
180def clean_township(town: str) -> str:
181    """
182    Normalize punctuation and spacing of township code and alias.
183
184    Args:
185        town: A single town or township
186
187    Returns:
188        Normalized township string, or unmodified string if input does not contain township
189        
190    Examples:
191        >>> clean_township('T4/R3 TWP')
192        'T4 R3'
193        
194        >>> clean_township('T10SD')
195        'T10 SD'
196        
197        >>> clean_township('CROSS LAKE TWP (T17 R5)')
198        'CROSS LAKE TWP T17 R5'
199    """
200    if is_unnamed_township(town) is False:
201        return town
202    else:
203        alias = extract_alias(town)
204        code = clean_code(town)
205        return ' '.join(filter(None, [alias, code]))
206    
207def strip_region(town: str) -> str:
208    return LAST_REGION_PATTERN.sub('', town)
209
210def strip_suffix(town: str) -> str:
211    """
212    Strips valid terminal suffix from town string.
213    
214    Context-sensitive: ignores suffix substrings if they are not in a valid 
215    suffix context.
216    
217    This method is used to generate plausible aliases for further testing.
218    Its intended use is alias generation and not routine cleanup.
219    
220    Args:
221        town: A single town or township
222        
223    Returns:
224        Town with valid terminal suffix stripped
225        
226    Examples:
227        >>> strip_suffix('RANGELEY PLANTATION')
228        'RANGELEY'
229        
230        >>> strip_suffix('Passamaquoddy Indian Township')
231        'Passamaquoddy Indian Township'
232        
233        >>> strip_suffix('Indian Stream Township')
234        'Indian Stream'
235        
236        >>> strip_suffix('Matinicus Isle Plt')
237        'Matinicus Isle'
238    """
239    return SUFFIX_PATTERN.sub('', town)
240
241def toggle_suffix(town: str, town_type: TownType = None) -> str:
242    """
243    Adds or removes a township suffix to grants, gores, and islands.
244
245    The TWP suffix is not canonical for all grants, gores, and islands.
246    This method is used to generate plausible aliases for further testing.
247    Its intended use is alias generation and not routine cleanup.
248
249    Args:
250        town: A single town or township
251        town_type: A `TownType` class. If provided, will increase accuracy.
252
253    Returns:
254        Gore, grant or island with township suffix added or removed, or else town
255
256    Examples:
257        >>> toggle_suffix('MOXIE GORE TWP')
258        'MOXIE GORE'
259        
260        >>> toggle_suffix('HOPKINS ACADEMY GRANT')
261        'HOPKINS ACADEMY GRANT TWP'
262        
263        >>> toggle_suffix('LOUDS ISLAND', TownType.UNORGANIZED)
264        'LOUDS ISLAND TWP'
265        
266        >>> toggle_suffix('CHEBEAGUE ISLAND', TownType.TOWN)
267        'CHEBEAGUE ISLAND'
268    """
269    if town_type not in (TownType.UNORGANIZED, TownType.ISLAND, None):
270        return town
271    elif ENDSWITH_JUNIOR_SUFFIX_PATTERN.match(town):
272        return town + match_case(' TWP', town)
273    elif CONTAINS_JUNIOR_SUFFIX_PATTERN.match(town):
274            return town[0:-4]
275    else:
276        return town
277    
278def normalize_suffix(town: str) -> str:
279    """
280    Normalize variations in geotype suffix abbreviation and location.
281
282    Does not alter pluralization. Pads suffix with whitespace if needed.
283    
284    Args:
285        town: A single town or township
286
287    Returns:
288        Town with normalized suffix
289
290    Examples:
291        >>> normalize_suffix('City of Portland')
292        'Portland'
293        
294        >>> normalize_suffix('MATINICUS ISLE PLANTATION')
295        'MATINICUS ISLE PLT'
296       
297        >>> normalize_suffix('MARIONTWPS')
298        'MARION TWPS'
299        
300        >>> normalize_suffix('Indian Township')
301        'Indian Twp'
302    """
303    gnis_format = GNIS_PATTERN.match(town.upper())
304    
305    if gnis_format is None:
306        town_name = town
307    else:
308        name = gnis_format.group('town')
309        suffix = ABBREVIATIONS.get(gnis_format.group('geotype'))
310        town_name = ' '.join(filter(None, [name, suffix]))
311
312    normalized = replace_all(SUFFIX_REPLACEMENTS, town_name, IGNORECASE)
313    return match_case(normalized, town, preserve_mixed_case=False)
314    
315def strip_town(town: str) -> str:
316    """
317    Strip invalid punctuation and whitespace from a town name substring.
318
319    This function performs the following operations:
320        1. Strip leading and trailing whitespace and squish internal whitespace
321        2. Replace ampersands ('&') that are recognized as part of a canonical town
322            name with 'and'
323        3. Strip all punctuation except hyphens ('-') that are recognized as 
324            part of a canonical town name
325
326    Args:
327        town: A single town or township
328
329    Returns:
330       Town name with punctuation stripped
331
332    Examples:
333        >>> strip_town("Loud's Island")
334        'Louds Island'
335        
336        >>> strip_town('Dover-Foxcroft -- ')
337        'Dover-Foxcroft'
338        
339        >>> strip_town('Taunton & Raynham Academy Grant')
340        'Taunton and Raynham Academy Grant'
341    """
342    town_name = normalize_whitespace(town)
343    town_name = VALID_AMPERSANDS_PATTERN.sub('and', town_name)
344    town_name = INVALID_PUNCTUATION_PATTERN.sub('', town_name)
345    town_name = town_name.strip()
346    return match_case(town_name, town, preserve_mixed_case=False)
347
348def clean_town(town: str) -> str:
349    """
350    Clean and format town name. 
351
352    Operations performed:
353        1. Strip or replace punctuation
354        2. Normalize whitespace
355        3. Abbreviate geotype suffixes
356        4. Normalize township codes
357
358    Args:
359        town: A single town or township
360
361    Returns:
362       Town name with punctuation stripped and formatting applied
363
364    Examples:
365        >>> clean_town('City of Portland')
366        'Portland'
367        
368        >>> clean_town('T8/R11 TWP')
369        'T8 R11'
370        
371        >>> clean_town('CROSS LAKE TWP (T17 R5)')
372        'CROSS LAKE TWP T17 R5'
373        
374        >>> clean_town('King & Bartlett Township')
375        'King and Bartlett Twp'
376        
377        >>> clean_town('MARIONTWPS ()')
378        'MARION TWPS'
379    """
380    cleaning_functions = [
381        strip_town
382        , normalize_suffix
383        , clean_township
384        , normalize_whitespace
385    ]
386    return chain_operations(town, cleaning_functions)
def is_unnamed_township(town: str) -> bool:
54def is_unnamed_township(town: str) -> bool:
55    """
56    Check if a string contains an unnamed township.
57
58    Args:
59        town: A single town or township
60        
61    Returns:
62        True if input contains an unnamed township, else False
63        
64    Examples:
65        >>> is_unnamed_township('T5 R7')
66        True
67        
68        >>> is_unnamed_township('CROSS LAKE TWP (T17 R5)')
69        True
70        
71        >>> is_unnamed_township('CROSS LAKE TWP')
72        False
73    """
74    return UNNAMED_PATTERN.search(town) is not None

Check if a string contains an unnamed township.

Arguments:
  • town: A single town or township
Returns:

True if input contains an unnamed township, else False

Examples:
>>> is_unnamed_township('T5 R7')
True
>>> is_unnamed_township('CROSS LAKE TWP (T17 R5)')
True
>>> is_unnamed_township('CROSS LAKE TWP')
False
def clean_code(town: str) -> str:
 76def clean_code(town: str) -> str:
 77    """
 78    Normalize punctuation and spacing of township code and drop text that is not part of the township code.
 79
 80    Args:
 81        town: A single town or township
 82
 83    Returns:
 84        Normalized township string, or unmodified string if input does not contain township
 85        
 86    Examples:
 87        >>> clean_code('T4/R3 TWP')
 88        'T4 R3'
 89        
 90        >>> clean_code('T10SD')
 91        'T10 SD'
 92        
 93        >>> clean_code('FLETCHERS LANDING TWP (T8 SD)')
 94        'T8 SD'
 95    """
 96    if is_unnamed_township(town) is False:
 97        return town
 98    else:
 99        elements = UNNAMED_ELEMENTS_PATTERN.findall(town)
100        formatted_elements = [CLEAN_TOWNSHIP_PATTERN.sub('', e) for e in elements]
101        return ' '.join(formatted_elements)

Normalize punctuation and spacing of township code and drop text that is not part of the township code.

Arguments:
  • town: A single town or township
Returns:

Normalized township string, or unmodified string if input does not contain township

Examples:
>>> clean_code('T4/R3 TWP')
'T4 R3'
>>> clean_code('T10SD')
'T10 SD'
>>> clean_code('FLETCHERS LANDING TWP (T8 SD)')
'T8 SD'
def clean_codes(towns: str) -> str:
103def clean_codes(towns: str) -> str:
104    """
105    Normalize punctation and spacing of township codes in-place.
106
107    Args:
108        towns: String with one or more towns or townships
109
110    Returns:
111        Input string with punctuation and spacing normalized for all township codes
112        
113    Examples:
114        >>> clean_codes('ASHLAND -- T12/R13, T9/R8')
115        'ASHLAND -- T12 R13, T9 R8'
116        
117        >>> clean_codes('T4/R3 TWP')
118        'T4 R3 TWP'
119        
120        >>> clean_codes('BARNARD TWP/EBEEMEE TWP (T5-R9 NWP)/T4R9 NWP TWP')
121        'BARNARD TWP/EBEEMEE TWP (T5 R9 NWP)/T4 R9 NWP TWP'
122    """
123    townships = UNNAMED_PATTERN.findall(towns)
124    cleaned = list(map(clean_code, townships))
125    return replace_all(dict(zip(townships, cleaned)), towns)

Normalize punctation and spacing of township codes in-place.

Arguments:
  • towns: String with one or more towns or townships
Returns:

Input string with punctuation and spacing normalized for all township codes

Examples:
>>> clean_codes('ASHLAND -- T12/R13, T9/R8')
'ASHLAND -- T12 R13, T9 R8'
>>> clean_codes('T4/R3 TWP')
'T4 R3 TWP'
>>> clean_codes('BARNARD TWP/EBEEMEE TWP (T5-R9 NWP)/T4R9 NWP TWP')
'BARNARD TWP/EBEEMEE TWP (T5 R9 NWP)/T4 R9 NWP TWP'
def has_alias(town: str) -> str:
127def has_alias(town: str) -> str:
128    """
129    Check if input has both an unnamed township and a township alias.
130
131    Args:
132        town: A single town or township
133
134    Returns:
135        True if town string contains a township code and alias, else False
136
137    Examples:
138        >>> has_alias('CROSS LAKE TWP (T17 R5)')
139        True
140        
141        >>> has_alias('EBEEMEE TWP')
142        False
143        
144        >>> has_alias('PRENTISS TWP T7 R3 NBPP')
145        True
146        
147        >>> has_alias('T7 R3 NBPP TWP')
148        False
149    """
150    if is_unnamed_township(town) is False:
151        return False
152    else:
153        return len(NON_ALIAS_PATTERN.sub('', town).strip()) > 0

Check if input has both an unnamed township and a township alias.

Arguments:
  • town: A single town or township
Returns:

True if town string contains a township code and alias, else False

Examples:
>>> has_alias('CROSS LAKE TWP (T17 R5)')
True
>>> has_alias('EBEEMEE TWP')
False
>>> has_alias('PRENTISS TWP T7 R3 NBPP')
True
>>> has_alias('T7 R3 NBPP TWP')
False
def extract_alias(town: str) -> str:
155def extract_alias(town: str) -> str:
156    """
157    Extract the township alias from a string that contains both an alias and a code.
158
159    Args:
160        town: A single town or township
161
162    Returns:
163        Input string with township code removed.
164
165    Examples:
166        >>> extract_alias('CROSS LAKE TWP (T17 R5)')
167        'CROSS LAKE TWP'
168        
169        >>> extract_alias('T3 Indian Purchase Twp')
170        'Indian Purchase Twp'
171        
172        >>> extract_alias('Rockwood Strip (T1 R1) Twp')
173        'Rockwood Strip Twp'
174        
175        >>> extract_alias('T7 R3 NBPP (PRENTISS TWP)')
176        'PRENTISS TWP'
177    """
178    if has_alias(town):
179        return squish(NON_ALIAS_PATTERN.sub('', town))    

Extract the township alias from a string that contains both an alias and a code.

Arguments:
  • town: A single town or township
Returns:

Input string with township code removed.

Examples:
>>> extract_alias('CROSS LAKE TWP (T17 R5)')
'CROSS LAKE TWP'
>>> extract_alias('T3 Indian Purchase Twp')
'Indian Purchase Twp'
>>> extract_alias('Rockwood Strip (T1 R1) Twp')
'Rockwood Strip Twp'
>>> extract_alias('T7 R3 NBPP (PRENTISS TWP)')
'PRENTISS TWP'
def clean_township(town: str) -> str:
181def clean_township(town: str) -> str:
182    """
183    Normalize punctuation and spacing of township code and alias.
184
185    Args:
186        town: A single town or township
187
188    Returns:
189        Normalized township string, or unmodified string if input does not contain township
190        
191    Examples:
192        >>> clean_township('T4/R3 TWP')
193        'T4 R3'
194        
195        >>> clean_township('T10SD')
196        'T10 SD'
197        
198        >>> clean_township('CROSS LAKE TWP (T17 R5)')
199        'CROSS LAKE TWP T17 R5'
200    """
201    if is_unnamed_township(town) is False:
202        return town
203    else:
204        alias = extract_alias(town)
205        code = clean_code(town)
206        return ' '.join(filter(None, [alias, code]))

Normalize punctuation and spacing of township code and alias.

Arguments:
  • town: A single town or township
Returns:

Normalized township string, or unmodified string if input does not contain township

Examples:
>>> clean_township('T4/R3 TWP')
'T4 R3'
>>> clean_township('T10SD')
'T10 SD'
>>> clean_township('CROSS LAKE TWP (T17 R5)')
'CROSS LAKE TWP T17 R5'
def strip_region(town: str) -> str:
208def strip_region(town: str) -> str:
209    return LAST_REGION_PATTERN.sub('', town)
def strip_suffix(town: str) -> str:
211def strip_suffix(town: str) -> str:
212    """
213    Strips valid terminal suffix from town string.
214    
215    Context-sensitive: ignores suffix substrings if they are not in a valid 
216    suffix context.
217    
218    This method is used to generate plausible aliases for further testing.
219    Its intended use is alias generation and not routine cleanup.
220    
221    Args:
222        town: A single town or township
223        
224    Returns:
225        Town with valid terminal suffix stripped
226        
227    Examples:
228        >>> strip_suffix('RANGELEY PLANTATION')
229        'RANGELEY'
230        
231        >>> strip_suffix('Passamaquoddy Indian Township')
232        'Passamaquoddy Indian Township'
233        
234        >>> strip_suffix('Indian Stream Township')
235        'Indian Stream'
236        
237        >>> strip_suffix('Matinicus Isle Plt')
238        'Matinicus Isle'
239    """
240    return SUFFIX_PATTERN.sub('', town)

Strips valid terminal suffix from town string.

Context-sensitive: ignores suffix substrings if they are not in a valid suffix context.

This method is used to generate plausible aliases for further testing. Its intended use is alias generation and not routine cleanup.

Arguments:
  • town: A single town or township
Returns:

Town with valid terminal suffix stripped

Examples:
>>> strip_suffix('RANGELEY PLANTATION')
'RANGELEY'
>>> strip_suffix('Passamaquoddy Indian Township')
'Passamaquoddy Indian Township'
>>> strip_suffix('Indian Stream Township')
'Indian Stream'
>>> strip_suffix('Matinicus Isle Plt')
'Matinicus Isle'
def toggle_suffix(town: str, town_type: mainegeo.entities.TownType = None) -> str:
242def toggle_suffix(town: str, town_type: TownType = None) -> str:
243    """
244    Adds or removes a township suffix to grants, gores, and islands.
245
246    The TWP suffix is not canonical for all grants, gores, and islands.
247    This method is used to generate plausible aliases for further testing.
248    Its intended use is alias generation and not routine cleanup.
249
250    Args:
251        town: A single town or township
252        town_type: A `TownType` class. If provided, will increase accuracy.
253
254    Returns:
255        Gore, grant or island with township suffix added or removed, or else town
256
257    Examples:
258        >>> toggle_suffix('MOXIE GORE TWP')
259        'MOXIE GORE'
260        
261        >>> toggle_suffix('HOPKINS ACADEMY GRANT')
262        'HOPKINS ACADEMY GRANT TWP'
263        
264        >>> toggle_suffix('LOUDS ISLAND', TownType.UNORGANIZED)
265        'LOUDS ISLAND TWP'
266        
267        >>> toggle_suffix('CHEBEAGUE ISLAND', TownType.TOWN)
268        'CHEBEAGUE ISLAND'
269    """
270    if town_type not in (TownType.UNORGANIZED, TownType.ISLAND, None):
271        return town
272    elif ENDSWITH_JUNIOR_SUFFIX_PATTERN.match(town):
273        return town + match_case(' TWP', town)
274    elif CONTAINS_JUNIOR_SUFFIX_PATTERN.match(town):
275            return town[0:-4]
276    else:
277        return town

Adds or removes a township suffix to grants, gores, and islands.

The TWP suffix is not canonical for all grants, gores, and islands. This method is used to generate plausible aliases for further testing. Its intended use is alias generation and not routine cleanup.

Arguments:
  • town: A single town or township
  • town_type: A TownType class. If provided, will increase accuracy.
Returns:

Gore, grant or island with township suffix added or removed, or else town

Examples:
>>> toggle_suffix('MOXIE GORE TWP')
'MOXIE GORE'
>>> toggle_suffix('HOPKINS ACADEMY GRANT')
'HOPKINS ACADEMY GRANT TWP'
>>> toggle_suffix('LOUDS ISLAND', TownType.UNORGANIZED)
'LOUDS ISLAND TWP'
>>> toggle_suffix('CHEBEAGUE ISLAND', TownType.TOWN)
'CHEBEAGUE ISLAND'
def normalize_suffix(town: str) -> str:
279def normalize_suffix(town: str) -> str:
280    """
281    Normalize variations in geotype suffix abbreviation and location.
282
283    Does not alter pluralization. Pads suffix with whitespace if needed.
284    
285    Args:
286        town: A single town or township
287
288    Returns:
289        Town with normalized suffix
290
291    Examples:
292        >>> normalize_suffix('City of Portland')
293        'Portland'
294        
295        >>> normalize_suffix('MATINICUS ISLE PLANTATION')
296        'MATINICUS ISLE PLT'
297       
298        >>> normalize_suffix('MARIONTWPS')
299        'MARION TWPS'
300        
301        >>> normalize_suffix('Indian Township')
302        'Indian Twp'
303    """
304    gnis_format = GNIS_PATTERN.match(town.upper())
305    
306    if gnis_format is None:
307        town_name = town
308    else:
309        name = gnis_format.group('town')
310        suffix = ABBREVIATIONS.get(gnis_format.group('geotype'))
311        town_name = ' '.join(filter(None, [name, suffix]))
312
313    normalized = replace_all(SUFFIX_REPLACEMENTS, town_name, IGNORECASE)
314    return match_case(normalized, town, preserve_mixed_case=False)

Normalize variations in geotype suffix abbreviation and location.

Does not alter pluralization. Pads suffix with whitespace if needed.

Arguments:
  • town: A single town or township
Returns:

Town with normalized suffix

Examples:
>>> normalize_suffix('City of Portland')
'Portland'
>>> normalize_suffix('MATINICUS ISLE PLANTATION')
'MATINICUS ISLE PLT'
>>> normalize_suffix('MARIONTWPS')
'MARION TWPS'
>>> normalize_suffix('Indian Township')
'Indian Twp'
def strip_town(town: str) -> str:
316def strip_town(town: str) -> str:
317    """
318    Strip invalid punctuation and whitespace from a town name substring.
319
320    This function performs the following operations:
321        1. Strip leading and trailing whitespace and squish internal whitespace
322        2. Replace ampersands ('&') that are recognized as part of a canonical town
323            name with 'and'
324        3. Strip all punctuation except hyphens ('-') that are recognized as 
325            part of a canonical town name
326
327    Args:
328        town: A single town or township
329
330    Returns:
331       Town name with punctuation stripped
332
333    Examples:
334        >>> strip_town("Loud's Island")
335        'Louds Island'
336        
337        >>> strip_town('Dover-Foxcroft -- ')
338        'Dover-Foxcroft'
339        
340        >>> strip_town('Taunton & Raynham Academy Grant')
341        'Taunton and Raynham Academy Grant'
342    """
343    town_name = normalize_whitespace(town)
344    town_name = VALID_AMPERSANDS_PATTERN.sub('and', town_name)
345    town_name = INVALID_PUNCTUATION_PATTERN.sub('', town_name)
346    town_name = town_name.strip()
347    return match_case(town_name, town, preserve_mixed_case=False)

Strip invalid punctuation and whitespace from a town name substring.

This function performs the following operations:
  1. Strip leading and trailing whitespace and squish internal whitespace
  2. Replace ampersands ('&') that are recognized as part of a canonical town name with 'and'
  3. Strip all punctuation except hyphens ('-') that are recognized as part of a canonical town name
Arguments:
  • town: A single town or township
Returns:

Town name with punctuation stripped

Examples:
>>> strip_town("Loud's Island")
'Louds Island'
>>> strip_town('Dover-Foxcroft -- ')
'Dover-Foxcroft'
>>> strip_town('Taunton & Raynham Academy Grant')
'Taunton and Raynham Academy Grant'
def clean_town(town: str) -> str:
349def clean_town(town: str) -> str:
350    """
351    Clean and format town name. 
352
353    Operations performed:
354        1. Strip or replace punctuation
355        2. Normalize whitespace
356        3. Abbreviate geotype suffixes
357        4. Normalize township codes
358
359    Args:
360        town: A single town or township
361
362    Returns:
363       Town name with punctuation stripped and formatting applied
364
365    Examples:
366        >>> clean_town('City of Portland')
367        'Portland'
368        
369        >>> clean_town('T8/R11 TWP')
370        'T8 R11'
371        
372        >>> clean_town('CROSS LAKE TWP (T17 R5)')
373        'CROSS LAKE TWP T17 R5'
374        
375        >>> clean_town('King & Bartlett Township')
376        'King and Bartlett Twp'
377        
378        >>> clean_town('MARIONTWPS ()')
379        'MARION TWPS'
380    """
381    cleaning_functions = [
382        strip_town
383        , normalize_suffix
384        , clean_township
385        , normalize_whitespace
386    ]
387    return chain_operations(town, cleaning_functions)

Clean and format town name.

Operations performed:
  1. Strip or replace punctuation
  2. Normalize whitespace
  3. Abbreviate geotype suffixes
  4. Normalize township codes
Arguments:
  • town: A single town or township
Returns:

Town name with punctuation stripped and formatting applied

Examples:
>>> clean_town('City of Portland')
'Portland'
>>> clean_town('T8/R11 TWP')
'T8 R11'
>>> clean_town('CROSS LAKE TWP (T17 R5)')
'CROSS LAKE TWP T17 R5'
>>> clean_town('King & Bartlett Township')
'King and Bartlett Twp'
>>> clean_town('MARIONTWPS ()')
'MARION TWPS'