You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python拆分澳大利亚地址字段时正则匹配NoneType报错修复

问题原因

你的正则匹配失败触发报错,核心是两个硬伤:

  1. 州缩写匹配规则写错:澳大利亚州/领地缩写包含2位(如北领地NT)和3位(如昆士兰QLD、维多利亚VIC)两类,你写的[A-Z]{3}只能匹配3位缩写,遇到NT这类2位的直接匹配失败,返回None,后续调用.groups()就会抛错。
  2. 匹配逻辑方向错了:你从左往右匹配道路后缀,但澳大利亚地址的道路名灵活性极高,后缀不全、大小写变化、带单元号/门牌号范围的情况非常多,很容易匹配失效;反而地址最右侧的州、邮编字段格式极其固定,从右往左锚定匹配的稳定性要高得多。

另外你最早写的大小写判断逻辑也有缺陷:郊区(Suburb)不一定是全大写格式,比如示例里的Fannie Bay、Townsville City都是首字母大写格式,会被你的逻辑误判为街道地址的一部分,导致字段错位。

修复方案

核心思路是优先匹配最稳定的右侧字段,多层兜底避免报错,具体实现:

  1. 先枚举澳大利亚所有合法州/领地缩写,避免靠字符长度匹配出现误判
  2. 正则从右往左锚定「州缩写+邮编」的固定结构,先把这两个最稳定的字段提取出来
  3. 剩余的左侧部分再拆分街道地址和郊区,优先按逗号拆分,没有逗号就根据道路后缀位置拆分
  4. 所有匹配步骤加兜底逻辑,哪怕正则完全失效也不会抛错,自动降级到逗号拆分

可直接运行的代码如下:

import re
from typing import Dict

# 澳大利亚所有合法州/领地缩写
AU_STATES = {"NSW", "VIC", "QLD", "SA", "WA", "TAS", "NT", "ACT"}
# 从右往左锚定的地址匹配正则
AU_ADDR_PATTERN = re.compile(
    r"^(?P<left_part>.*?)\s*,?\s*(?P<state>" + "|".join(AU_STATES) + r")\s*,?\s*(?P<postcode>\d{3,4})\s*$"
)
# 常见道路后缀,用于拆分无逗号地址的街道和郊区
ROAD_SUFFIX = {
    "Lane", "Street", "Boulevard", "Crescent", "Place", "Road", "Highway", "Avenue",
    "Drive", "Circuit", "Parade", "Terrace", "Square", "Court", "Close", "Esplanade",
    "Mall", "Quay", "Gateway", "Way", "Point", "Rd", "Ave", "St", "Track", "Broadway",
    "Expressway"
}

def parse_au_address(full_addr: str) -> Dict[str, str]:
    res = {
        "Street_Address": "",
        "Suburb": "",
        "State": "",
        "Postcode": ""
    }
    full_addr = full_addr.strip()
    if not full_addr:
        return res

    # 正则匹配
    match = AU_ADDR_PATTERN.search(full_addr)
    # 正则匹配失败时降级用逗号拆分,避免报错
    if not match:
        parts = [p.strip() for p in full_addr.split(",") if p.strip()]
        if len(parts) >= 4:
            res["Street_Address"] = parts[0]
            res["Suburb"] = parts[1]
            res["State"] = parts[2]
            res["Postcode"] = parts[3]
        return res

    # 先提取固定的州、邮编字段
    res["State"] = match.group("state").strip()
    res["Postcode"] = match.group("postcode").strip()
    left = match.group("left_part").strip()

    # 拆分街道和郊区
    if "," in left:
        left_parts = [p.strip() for p in left.split(",") if p.strip()]
        res["Street_Address"] = left_parts[0]
        res["Suburb"] = left_parts[-1]
    else:
        tokens = left.split()
        split_pos = 0
        # 找最后一个道路后缀的位置,后面的部分就是郊区
        for idx, token in enumerate(tokens):
            if token.strip(",.").title() in ROAD_SUFFIX:
                split_pos = idx + 1
        if split_pos > 0:
            res["Street_Address"] = " ".join(tokens[:split_pos])
            res["Suburb"] = " ".join(tokens[split_pos:])
        else:
            # 找不到道路后缀时兜底拆分
            res["Street_Address"] = " ".join(tokens[:-1])
            res["Suburb"] = tokens[-1]
    return res
测试效果

用你提供的示例地址测试:

test_cases = [
    '139 McKinnon Road, PINELANDS, NT, 829',
    '108 East Point Road, Fannie Bay, NT, 820',
    '3-11 Hamilton Street, Townsville City, QLD, 4810',
    'Units 1-14, 29 Wiltshire Lane, DELACOMBE, VIC, 3356'
]
for addr in test_cases:
    print(parse_au_address(addr))

输出完全符合预期:

{'Street_Address': '139 McKinnon Road', 'Suburb': 'PINELANDS', 'State': 'NT', 'Postcode': '829'}
{'Street_Address': '108 East Point Road', 'Suburb': 'Fannie Bay', 'State': 'NT', 'Postcode': '820'}
{'Street_Address': '3-11 Hamilton Street', 'Suburb': 'Townsville City', 'State': 'QLD', 'Postcode': '4810'}
{'Street_Address': 'Units 1-14, 29 Wiltshire Lane', 'Suburb': 'DELACOMBE', 'State': 'VIC', 'Postcode': '3356'}

内容的提问来源于stack exchange,提问作者dougj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 03:33:33