这是快递分拣工具输入地址按设定的规则自动匹配到对应的配送站点。python# -*- coding: utf-8 -*-快递按收货地址自动分拣核心思路:每条规则描述一个站点负责的范围(省/市/区 关键词),分拣时对所有规则打分,取「优先级最高、匹配最精确」的那条。import refrom collections import defaultdictfrom dataclasses import dataclassfrom typing import Iterable, List, Optional, Sequence, Tuple# ---------------- 1. 地址归一化 ----------------_FULL_TO_HALF str.maketrans(,0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz,)def normalize(address: str) - str:全角转半角 去掉空白和常见分隔符,让「北京市 朝阳区」「北京市,朝阳区」和「北京市朝阳区」等价。if not address:return s address.translate(_FULL_TO_HALF)return re.sub(r[\s,.。;、\-—_/\\|()【】\[\]], , s)# ---------------- 2. 分拣规则 ----------------dataclassclass Rule:一条分拣规则:某个站点负责的地址范围site: str # 目标配送站 / 分拨中心province: str city: str district: str keywords: Tuple[str, ...] () # 街道、乡镇、园区等priority: int 0 # 越大越优先,用于强制覆盖def __post_init__(self):# 规则里的地址同样要归一化,保证和收件地址同一套写法self.province normalize(self.province)self.city normalize(self.city)self.district normalize(self.district)self.keywords tuple(normalize(k) for k in self.keywords if k)def match_score(self, addr: str) - Optional[int]:addr 必须已归一化。命中返回得分(越高越精确),不命中返回 None。打分逻辑:- 规则里填写的省 / 市 / 区,必须全部出现在地址中(硬约束);- 命中的层级越多,分数越高(省 100、市 50、区 20);- 关键词每命中一个 5,用于同区内再细分。if not any((self.province, self.city, self.district, self.keywords)):return Nonescore 0for value, weight in ((self.province, 100), (self.city, 50), (self.district, 20)):if value:if value not in addr:return Nonescore weightfor kw in self.keywords:if kw in addr:score 5return score or None# ---------------- 3. 分拣器 ----------------dataclassclass SortResult:address: strsite: strmatched: boolrule: Optional[Rule] Noneclass AddressSorter:def __init__(self, rules: Sequence[Rule], default_site: str 人工分拣区):self.rules list(rules)self.default_site default_sitedef sort(self, address: str) - SortResult:addr normalize(address)best_rule, best_key None, Nonefor rule in self.rules:score rule.match_score(addr)if score is None:continuekey (rule.priority, score) # 先比优先级,再比精确度if best_key is None or key best_key: # 同分时先注册的规则胜出best_rule, best_key rule, keyif best_rule is None:return SortResult(address, self.default_site, False, None)return SortResult(address, best_rule.site, True, best_rule)def sort_batch(self, addresses: Iterable[str]) - List[SortResult]:return [self.sort(a) for a in addresses]# ---------------- 4. 规则配置 使用示例 ----------------RULES: List[Rule] [# 北京:朝阳区内再细分出「望京站」Rule(site北京-望京站, province北京, city北京, district朝阳区,keywords(望京, 酒仙桥, 大山子, 阜通, 来广营)),Rule(site北京-朝阳站, province北京, city北京, district朝阳区),Rule(site北京-海淀站, province北京, city北京, district海淀区),# 上海Rule(site上海-虹桥站, province上海, city上海, district闵行区,keywords(虹桥, 华漕, 七宝)),Rule(site上海-浦东站, province上海, city上海, district浦东新区),# 广东Rule(site广州-天河站, province广东, city广州, district天河区),Rule(site深圳-南山站, province广东, city深圳, district南山区),# 注意:全国有两个「朝阳」——靠省市区三级约束区分Rule(site辽宁-朝阳站, province辽宁, city朝阳, district双塔区),]if __name__ __main__:sorter AddressSorter(RULES, default_site北京-人工分拣)addresses [北京市朝阳区望京街道阜通东大街6号,北京市朝阳区建国路88号SOHO现代城,北京市海淀区中关村大街1号,上海市闵行区虹桥火车站出发层,上海市浦东新区世纪大道100号,广东省广州市天河区体育西路103号,广东省深圳市南山区科技园南区,辽宁省朝阳市双塔区新华路1号,火星基地一号舱, # 匹配不到 → 兜底]results sorter.sort_batch(addresses)print( 逐单分拣结果 )for r in results:flag ✔ if r.matched else ✘print(f{flag} {r.address} - {r.site})print(\n 按站点汇总(实际装车用))groups defaultdict(list)for r in results:groups[r.site].append(r.address)for site, addrs in groups.items():print(f\n【{site}】共 {len(addrs)} 单)for a in addrs:print(f - {a})分拣逻辑与操作说明这段代码就像一个智能分拣员收到地址后按您定义的规则自动匹配站点并给出最终去向。· 地址归一化先把全角字符、空格和标点统一成半角并去掉分隔符避免“北京市 朝阳区”和“北京市朝阳区”被当成不同地址。· 规则匹配每条规则包含省、市、区、关键词和优先级省市区必须全部命中才有效命中的层级越多得分越高关键词每命中一个再加分。· 判定与兜底所有规则中得分最高且优先级最高的胜出如果没有任何规则命中自动归入“人工分拣区”。· 结果展示逐单显示匹配结果✔或✘并按站点汇总每个配送站需要装车的订单。---优化建议 规则配置集中在代码末尾的 RULES 列表中可以按同样的格式增删站点和区域批量测试地址就在下面的 addresses 列表里修改。文章仅供参考用。
阅读完成 · 觉得有帮助?