写证件号校验时,最容易出现的误解是把「格式正确」和「号码有效」当成一件事。长度对了、字符集对了,代码就返回通过;可业务方说的有效,往往还包括校验位能不能算对、以及这个号码在现实中是否存在。
格式与校验位是两件独立的事
格式描述号码长什么样:总长度、允许的字符、分组方式、各部分的位置。校验位描述号码内部的数字之间是否满足某个算术关系。
两者可以任意组合。一个长度和字符集都完全正确的号码,校验位可能算不过;一个校验位完全算对的号码,也可能根本没有被签发过。把这两层分开处理,代码的错误信息才有意义:格式错就报格式错,校验位错就报校验位错,不要笼统地回一句「号码无效」。
这个区分还能避免一类返工:产品经理希望系统能判断号码「是不是真的」,而这个能力在多数地区并不存在公开可用的判定方式。诚实地说清楚能验到什么程度,比含糊地拒绝一个合法号码要好。
校验位到底能证明什么?
它能证明的只有一件事:这个号码的数字排列没有因为随手输入或随机生成而破坏内部的一致性。
它不能证明的是:号码是否被真实签发、是否属于填写者本人、是否仍在有效期内。这三点需要发证机构或官方数据库才能判断,不在算法能力范围内。
因此校验位的作用是挡掉输入错误和机器随机生成的脏数据。它能显著降低表单里的无效提交,也会让测试数据一旦是随机拼出来的就立刻暴露,因为随机数字几乎不可能碰巧满足校验关系。
常见的几类校验算法
一类是取模运算。做法是把号码的前若干位按固定权重加权求和,再对某个模数取余,把余数映射成最后一位或两位。多位校验位就是对同一组数字做两次不同的取模。这类算法在同一国家的不同证件上可能重合,但权重和模数各不相同,实现时必须逐个确认。
一类是字母映射。号码的最后一位是字母,做法是先把前几位的数字对模数取余,再把余数映射到一张字母表上。这类算法的关键是字母表本身,而不是长度,改一个字母表就会让结果整体变化。
一类是逐段结构校验。号码由若干段组成,每段有各自的字符集和含义,合法性判断来自各段是否同时成立,而不是整体算一个校验位。
一类是纯格式校验。只有长度和字符集要求,没有公开的校验算法。这类号码只能做到形状检查,任何声称能校验其有效性的实现都需要说明依据。
还有一类是跨字段校验。校验位与号码内部编码的信息需要与表单里的其它字段对应,比如号码里含出生日期段、而表单里另有出生日期字段。这类校验属于字段之间的一致性,和纯格式检查不是一回事,相关思路可以参考测试数据里的字段自洽。
| 算法类型 | 判定依据 | 主要边界 |
|---|---|---|
| 取模运算 | 加权求和后取余 | 权重与模数需逐国确认 |
| 字母映射 | 余数映射到字母表 | 字母表错误则全体失效 |
| 逐段结构 | 各段同时成立 | 段含义需按官方说明 |
| 纯格式 | 长度与字符集 | 无法判断有效性 |
| 跨字段 | 与其它字段对应 | 属于一致性检查 |
举一个可推演的例子
要说明校验位怎么工作,用一组明显虚构的数字就够了:假设前若干位的加权求和结果对模数取余得到 3,那么最后一位就应当是 3。改动其中任意一位,余数就会变化,最后一位随之下匹配,算法立刻报错。
真实的证件号码一律不要出现在测试数据、缺陷报告或截图里,即使号码属于你自己。替代做法是用工具按公开算法构造校验位正确的虚构号码,它们格式合规、校验通过,同时明确不是任何真实个人或机构的编号。
需要批量构造这类号码时,号码校验工具可以按地区规则生成并通过同一套算法反向验证;如果还需要与地址、邮箱等字段保持一致,身份信息生成器可以让证件号、生日和姓名出自同一条记录,避免字段之间互相矛盾。
在自己的系统里该怎么测?
测试的重点不是背下各地区的算法,而是确认你的实现边界在哪里。
- 长度少一位、多一位时,错误信息是否指向长度而不是笼统的无效;
- 把中间任意一位数字改掉时,校验位类算法是否回报校验失败;
- 末尾是字母的号码,小写输入是否被正确接受或明确拒绝;
- 只有格式要求的地区,实现是否克制地只做形状检查;
- 号码内含有日期段时,该段与出生日期字段不一致是否被发现;
- 输入前后有空格或分隔符时,规范化行为是否与文档一致;
- 同一地区存在多种证件类型时,是否能区分而不是用一套规则覆盖全部。
用校验位算法概览可以对上各类算法的判定口径,用号码校验的工作原理确认你的实现把哪一层当成了通过条件。测试用例的组织方式还可以参照批量校验的工作流,把单条断言和批量回归分开。
遇到没有校验算法的地区怎么办?
不要为了「看起来更严格」而发明一套规则。捏造校验算法最直接的后果是拒绝合法的号码,而这类拒绝往往在很晚才被真实用户发现。
可行的做法是明确分层:格式检查始终执行;校验位只在确有公开算法时执行;有效性判定如果确实需要,就走官方接口或人工审核,并把它标注为另一条流程。这三层的提示文案也要分开,让调用方知道拒绝的原因属于哪一层,不含校验位的号码里对这类纯格式地区有更细的说明。
常见问题
校验通过的号码可以当作真实号码使用吗?
绝对不可以。校验通过只说明数字排列自洽,与是否真实存在无关。构造出来的号码用于测试路径没问题,但不能写进任何对外提交、申报或核验场景。
为什么同一个号码在两个网站上结论不同?
多半是两个系统对「有效」的定义不同:一个只查格式,另一个查校验位,还有的接了官方接口。结论不同不代表其中一方写错了,先确认双方的判定层级,再判断是不是缺陷。
需要把所有地区的算法都实现一遍吗?
不需要。按业务实际覆盖的地区来,未覆盖的地区明确降级为格式检查。把「未实现」和「实现但校验失败」混在同一个错误码里,会让后续排查非常痛苦。
随机生成的测试数据为什么总被拒绝?
因为随机数字几乎不可能满足校验关系。这是正常现象,说明校验逻辑生效了。要造出能通过的样本,需要用同一套算法反向构造,而不是随机拼长度。
本文讨论的是号码校验的算法分层与测试方法,不构成对任何国家或地区证件签发规则、法律效力或身份核验要求的说明;文中出现的数字均为说明原理的虚构示例,不代表任何真实个人或机构的编号。