diff --git a/convert-addresses.py b/convert-addresses.py index 58f3263..30aa121 100644 --- a/convert-addresses.py +++ b/convert-addresses.py @@ -52,14 +52,17 @@ def process_address_fields(gdf, exceptions): mapping['addr:housenumber'] = series.round().astype('Int64') break - # Unit + # Unit (a dedicated column takes priority; otherwise fall back to a unit + # designator embedded in a combined street+unit address string below) + unit_from_column = [None] * len(processed) for field in ['UNIT', 'UnitNumber', 'UNIT_NUM', 'APT']: if field in processed.columns: series = processed[field].copy().replace(['nan', 'None', '', None], None) - mapping['addr:unit'] = series.where(series.notna(), None) + unit_from_column = list(series.where(series.notna(), None)) break # Street name + unit_from_address = [None] * len(processed) if 'SADD' in processed.columns: # Sumter: full address string in SADD mapping['addr:street'] = [ @@ -67,6 +70,11 @@ def process_address_fields(gdf, exceptions): if pd.notna(v) else None for v in processed['SADD'] ] + unit_from_address = [ + qgis_functions.title(qgis_functions.getunitfromaddress(str(v), None, None) or '') or None + if pd.notna(v) else None + for v in processed['SADD'] + ] elif 'FullAddres' in processed.columns: # Lake: full address string in FullAddres mapping['addr:street'] = [ @@ -74,6 +82,11 @@ def process_address_fields(gdf, exceptions): if pd.notna(v) else None for v in processed['FullAddres'] ] + unit_from_address = [ + qgis_functions.title(qgis_functions.getunitfromaddress(str(v), None, None) or '') or None + if pd.notna(v) else None + for v in processed['FullAddres'] + ] elif 'BaseStreet' in processed.columns: # Lake alternative: assemble from components street_names = [] @@ -85,6 +98,11 @@ def process_address_fields(gdf, exceptions): street_names.append(qgis_functions.title(' '.join(parts)) if parts else None) mapping['addr:street'] = street_names + mapping['addr:unit'] = [ + col if col is not None else addr + for col, addr in zip(unit_from_column, unit_from_address) + ] + # Apply street name exceptions if 'addr:street' in mapping and exceptions: mapping['addr:street'] = [ diff --git a/qgis-functions.py b/qgis-functions.py index 838215f..a459853 100644 --- a/qgis-functions.py +++ b/qgis-functions.py @@ -21,13 +21,32 @@ def title(s): result = re.sub(pattern, replacement, result) return result +# Secondary unit designators that may appear inline in a full address string, +# e.g. "123 ROLLING ACRES RD UNIT 208" - everything from the designator on is +# the unit, not part of the street name. +_UNIT_DESIGNATORS = {'UNIT', 'APT', 'APARTMENT', 'STE', 'SUITE', 'BLDG', 'BUILDING', 'LOT'} + +def _splitunit(parts): + for i, part in enumerate(parts): + if part.upper().rstrip('.') in _UNIT_DESIGNATORS: + return parts[:i], (" ".join(parts[i + 1:]) or None) + return parts, None + # @qgsfunction(args='auto', group='Custom', referenced_columns=[]) def getstreetfromaddress(value1, feature, parent): parts = value1.split() parts.pop(0) # Ignore the first bit (i.e. "123" in "123 N MAIN ST") + street_parts, _ = _splitunit(parts) #parts = map(formatstreetname, parts) #return " ".join(parts) - return formatstreet(" ".join(parts), None, None) + return formatstreet(" ".join(street_parts), None, None) + +# @qgsfunction(args='auto', group='Custom', referenced_columns=[]) +def getunitfromaddress(value1, feature, parent): + parts = value1.split() + parts.pop(0) # Ignore the first bit (i.e. "123" in "123 N MAIN ST") + _, unit = _splitunit(parts) + return unit # @qgsfunction(args='auto', group='Custom', referenced_columns=[]) def formatstreet(value1, feature, parent):