用户操作层面的国家码问题,已经写在 全球号码批量去重。这篇给做系统的人:全球号码去重系统 的格式引擎要先于页面存在。规则写错,分布式和秒级查询只是把错误结果更快送出去。
不要把“去掉非数字字符再 strcmp”当成全球去重。那只对已经统一写成 E.164 的数据有效。你接到的文件几乎都不是。
先处理输入,再谈地区
同一单元格可能含空格、括号、短横、点、以及开头的 + / 00 / 011(美国国际冠码)。建议顺序:
- 去掉空白和常见分隔符,保留开头的
+信息(或先记录“是否以 + / 00 开头”再去符号) - 把
00、011这类国际冠码收成“已带国家码” - 若已带国家码,以号码自带地区为准,而不是任务默认地区
- 若没带,才用任务的默认地区去补
第 3、4 步反了,一批已写 +66 的泰国号会被按中国 11 位切掉。这是全球号码去重系统里最贵的一类 bug:看起来“处理成功”,键全错。
默认地区必须是任务级参数
系统不要只有一个全局 DEFAULT_REGION=CN。跨境团队同一天会跑英国包和东南亚包。默认地区写在任务上,界面上要让人看见,导出里也要带回,事后才查得清。
没选默认地区且号码没带国家码的行,进异常,不要猜测。猜测会进库,库脏了比漏处理更麻烦。
前导 0 不能全球一刀切
英国、泰国等地的本地拨号带 trunk prefix 0,国际格式里这个 0 要去掉再加国家码。中国大陆手机号 11 位,前面补 86,并不走同一套“去 0”逻辑。
把“所有开头的 0 都删”写成一行代码,会伤害:
- 意大利等仍可能用 0 开头的号段
- 已经是国际格式、中间恰好出现 0 的号(少见但不要用全局 strip)
正确做法是:识别地区后,按该地区的规则处理 national number,而不是对整串做 lstrip('0')。
号长用元数据,不要用 if-else 堆国家
CN=11、US=10 这种表,写进代码的第二年就会过期。号段开放、部分国家手机号长度本来就有区间。
更稳的做法:
- 使用可更新的地区元数据(许多实现会参考 libphonenumber 的 metadata)
- 元数据包打版本,和比对键规则版本一起记在任务上
- 校验失败进异常,不要截断后强行入库
自己维护一份“我们业务覆盖的 30 个国家”的精简表也可以,但要有人负责更新,并在元数据变更后提供重算工具。不重算,新旧键会并存,去重率看起来下降,其实是规则分裂。
严格模式和宽松模式要分开,不要一个开关打天下
演示里常见“全球号码 / 严格去重”,背后是两种风险偏好:
- 全球/常规: 能识别地区就收键,便于营销名单快速出通过号
- 严格: 号长、号段、可能的地区歧义,一律进异常或待人工,降低误合并
系统里这应是任务模式,而不是改内核 if。同一套规范化函数,不同的失败策略。用户侧误区见 号码去重复工具常见误区。
存储时同时留下“解析轨迹”
全球号码去重系统出了误判,开发最怕的是只看到最终键。建议每条至少能回看:
- 原值
- 判定的地区来源(号码自带 / 任务默认 / 失败)
- 用的元数据版本
- 失败原因码(too_short、invalid_country_code、excel_scientific 等)
没有原因码,运营只会告诉你“这批不对”,你只能重新猜。表结构配合见 号码数据库系统。
制作流程上的两个技术点子
先单测国家,再接文件。 把每个覆盖国家的 5~10 种写法做成固定测试,CI 里跑。文件解析的 bug 和规则 bug 混在一起时,定位成本会翻倍。验收样本类型见 号码数据去重软件怎么验收。
不要在查询时现场 parse。 入库前完成规范化,查询只走键上的索引。亿级时现场解析会把 CPU 打满,而且同一原值在不同默认地区下结果还可能变。规模问题见 亿级号码秒级去重。
产品能力里的多地区格式,对应 核心功能;任务和并发对应 底层架构。
常见问题
必须覆盖 180 多个地区才能叫全球号码去重系统吗?
不必。先覆盖你实际触达的国家,元数据按包升级。但引擎要按“地区规则”来设计,不要做成“中国逻辑 + 几个特例”。
号码带了错误的国家码怎么办?
以号码自带为准还是以任务为准,要在规则里写死。常见策略:已带 + 或 00 的信任号码;明显不可能的国家码进异常。不要两边各猜一次再合并。
从哪看多地区任务怎么跑?
在线 Demo 里用带混写国家码的样本看结果分类。按地区包部署联系 Telegram @imchat。