条形码校验位的原理 (EAN-13、UPC-A、EAN-8)
你买的几乎每件商品的条形码,其最后一位数字其实根本不属于商品编号 — 它是校验位,一个由其余数字计算出来、用于发现扫描和输入错误的单个数字。本指南通过一个可以手动跟着算的例子,讲解这个数字在三种最常见的零售格式 — EAN-13、UPC-A 和 EAN-8 — 中是如何工作的。
校验位有什么用
校验位是一种内置的冗余。条形码的数据位已经标识了商品; 校验位并不增加关于商品本身的新信息。相反,它编码了一种必须在所有数字之间成立的关系,因此当扫描器误读某条码线、或有人输错号码时,这种关系就会被破坏,错误会被立即发现,而不是被悄悄接受。
零售条形码采用的方案是 GS1 模 10。由于收银扫描器每天要即时而可靠地校验数千次,它被刻意设计得很简单 — 几次乘法和一次减法。
GS1 模 10 算法
取除最后校验位之外的所有数字。从这些数据位的最右侧开始向左,将各位交替乘以 3 和 1。把所有乘积相加。校验位就是你需要加到这个和上、使其达到下一个 10 的倍数的那个值。
写成公式: 校验位 = (10 − (加权和 mod 10)) mod 10。外层的 'mod 10' 处理和本身已是 10 的倍数的情形,此时校验位为 0。
- 权重从最右侧数据位开始交替为 3、1、3、1 ……
- 只有最后一位是校验位; 它之前的全是数据。
- EAN-13、UPC-A 和 EAN-8 都使用相同算法,只是长度不同。
一个算例
取 EAN-13 数据 400638133393(12 位; 第 13 位将是校验位)。从右侧读起并按 3、1、3、1 …… 加权,乘积为 3×3 + 9×1 + 3×3 + 3×1 + 3×3 + 1×1 + 8×3 + 3×1 + 6×3 + 0×1 + 0×3 + 4×1,相加得 89。
89 之上的下一个 10 的倍数是 90,所以校验位是 90 − 89 = 1。完整有效的条形码是 4006381333931。如果扫描器把最后一位读成了 7,重新计算的校验位就会不匹配,读取会当场被拒绝。
为什么用 3 加权能发现更多错误
交替使用 3 这个权重并非随意。单纯把各位相加也能发现任意一位的错误,但会漏掉一种非常常见的人为错误: 把相邻两位调换,比如把 21 打成 12。把交替位置乘以 3,会让被调换的相邻两位获得不同的权重,因此大多数调换都会改变总和并被发现。
任何单个校验位都无法发现所有可能的错误 — 权重为 3 的模 10 会漏掉相差为 5 的两位调换,以及恰好相互抵消的两个错误。它是针对最常见错误的廉价而快速的防护,而非密码学意义上的保证。
EAN-13、UPC-A 与 EAN-8
三种格式只在长度上不同。EAN-13 有 12 位数据加 1 位校验,是全球标准。北美常见的 UPC-A 有 11 位数据加 1 位校验 — 实际上就是前面加了一个 0 的 EAN-13。EAN-8 把 7 位数据加 1 位校验压缩进更短的符号,用于放不下完整条形码的小件商品。
由于它们共享模 10 算法,同一计算即可校验三者; 你只需知道应有多少位。以条形码形式印刷的 13 位 ISBN 也是 EAN-13,使用的正是这个校验位,所以一本书的条形码可以用和一罐豆子相同的方式来校验。