商品条形码最后一位怎么来的?Code128 校验位实测

0 阅读9分钟

我往页面里填了一串 12 位编号 690123456789,它自己把最后一位算了出来:应该是 58。

算的过程也贴在屏幕上。起始符码值 105,六组数字的加权和 1189,加起来 1294,除以 103 余 58。

同一串编号用 Code C 编,一共 101 个模块、9 个符号位、含静区 242 像素宽;换成 Code A 或者 Code B,同样的内容要 167 个模块、374 像素。

图 1:默认输入 690123456789,页面给出校验位、模块数、总宽度,右上角是 8 项自检徽章

在线案例与源码:atomgit.com/deli007/dem… 成品只有一个 index.html,双击就能打开。下面每个数字都是我在页面里读回来、又用一份 Python 脚本复算过的。

一、为什么值得搞清楚:最后一位不是随便编的

结论先放这:一维条码的最后一位是算出来的校验位,不是流水号。

公式只有一句话,起始符的码值,加上每个数据符「码值 × 序号」之和,再对 103 取余。

我把它拆成五步显示在页面上,从起始符一直写到校验字符,每一步的中间结果都留在屏幕上。

我第一次认真看这个规则,是因为打印机打出来一串编号,扫码枪偶尔读不出来。

当时以为是条码太窄,其实是校验位和前面的数据对不上,扫码枪算完直接判无效。

这个规则的价值也在这儿:读错的条码会当场被揭穿,而不是安静地给出一个错号。

图 2:校验位分步计算,第 1 步到第 5 步都带中间数字

二、准备环境:进入码道 Web,把「要能自己算数」写进需求

浏览器打开码道 Web 版:devcloud.cn-north-4.huaweicloud.com/chat?source… ,登录后在对话框里写下需求,就能拿到一个能跑的单文件应用,不用装软件。

码道有三种使用方式:WebUI(浏览器对话)、TUI(终端命令行)和桌面 IDE(IDE 插件)。本文用 WebUI 版演示。

这轮需求里最值钱的是这几句。

  • 107 项码值图案表直接给全,别让它自己回忆,回忆出来的表格没法信。
  • 五个面板都要,输入参数、编码明细、校验分步、字符集对比、解码自检。
  • 页面自己带自检,通过和失败的条数显示在角上。

第三句是这次的关键。一个算校验位的页面,光看结果分不出对错,只有它自己敢报「我算了几项、错了几项」,我才好判断。

三、一屏看清:五个面板加一枚自检徽章

页面从上往下是五块。

第一块是输入与参数:编号、字符集 A/B/C、模块宽度、静区模块数。

第二块是条码预览,用内联 SVG 画的,下面挂着编号文本。

第三块是编码明细表,按起始符、数据符、校验符、终止符列出来,每行给字符、码值、条空宽度图案和一小段图形。

第四块是校验位分步计算,第五块是解码自检和字符集对比。

右上角的徽章是 8 项页面自检的结果,全过就是绿色的 8 / 8。

四、实测:12 位编号的完整码值序列

Code C 每两位数字并成一个数据符,6 组数字正好 6 个数据符。

角色字符码值条空宽度图案
起始符起始 C105211232
数据 16969112214
数据 2011222122
数据 32323312131
数据 44545113123
数据 56767141122
数据 68989212141
校验符数字对 5858312311
终止符STOP1072331112

校验位的每一步我也抄了下来。

步骤内容数值
起始符码值起始 C 直接计入105
乘积项69×1、1×2、23×3、45×4、67×5、89×669、2、69、180、335、534
累加105 + 11891294
取余1294 mod 10358
校验符码值 58 对应图案312311

图案这一列是条空的宽窄,数字 1 到 4 表示这个条或者空占几个模块。

起始符的 211232 拆开就是两模块黑、一模块白、一模块黑、两模块白、三模块黑、两模块白。

把这些段落首尾接起来,就是条码本体。

五、字符集对照:Code C 为什么能省四成模块

同一串 690123456789,三种字符集的尺寸差得很明显。

字符集可编码符号位数总模块数总宽度(含静区)
Code A可编码15167374 px
Code B可编码15167374 px
Code C可编码9101242 px

Code A 和 Code B 一个字符一个数据符,12 位数字就是 12 个数据符。

Code C 每两位并一个,只剩 6 个。

结果是 167 变 101,少了 66 个模块,约 39.5%;宽度从 374 像素压到 242 像素,省 35.3%。

模块数还有个固定公式可以核对:11 乘符号位数再加 13。

9 个符号位就是 11 × 8 + 13 = 101,那 13 是终止符占的。

加上左右各 10 个模块的静区,位图长度正好 121,页面自检里也是这个数。

图 3:字符集对比表高亮最短方案,下面是解码自检和 8 项页面自检

六、解码自检:把条空宽度反过来读一遍

只算不读,是没法确认的。

页面的解码路径是位图游程、条空宽度序列、码值查表、起始符定集、字符映射,一路倒着走回去。

它读出来的文本还是 690123456789,与输入完全一致。

这一趟连编码带位图带 SVG 渲染,页面自己记的耗时是 0.70 毫秒。

这个数字是页面用脚本里的计时器量的,量的是浏览器里的计算和绘制,不是扫码枪的识读速度。

右上角那 8 项自检里,跟这条有关的是三项:解码码值序列与编码逐项一致、反向解码文本与输入一致、终止符与静区参与后的位图长度对不对。

七、字符集不是越大越好:换一种输入看宽窄

我把输入换成 hello-2026,字符集选 Code B。

结果是 13 个符号位、145 个模块、330 像素。

换成 HELLO 加 Code A,是 8 个符号位、90 个模块、220 像素。

换回纯数字 12 加 Code C,只要 4 个符号位、46 个模块、132 像素;0012 是 5 个符号位、57 个模块、154 像素。

这四组数据放在一起能看出一个取舍:数字越多,Code C 越划算;字母一多,Code A 和 Code B 才是唯一选择。

图 4:同一串编号改用 Code A 编码,符号位从 9 涨到 15,条码明显变宽

八、验证与踩坑:31 项复算,四类非法输入

我不信页面自己报的 8 / 8,所以另写了一份 Python 脚本做独立复算,它按同样的规则重算了码表完整性和各组尺寸。

脚本跑出来 31 / 31 项一致,含码表 107 项、模式互不重复、每组输入的符号位、模块数、宽度和校验值。

脚本在案例目录里,命令是这两行。

cd codearts-barcode-generator
python verify_code128.py

失败路径我用四组输入挨个试了。

输入字符集页面反馈
69012345678Code C要求数字个数为偶数,每两位编为一个数据符
ABC123Code C仅支持数字字符 0 到 9
abc-123Code A字符「a」的 ASCII 97 不被 Code A 支持
空输入Code C输入不能为空

这四次里徽章从 8 / 8 掉到 7 / 8,多了一项失败,条码和面板都保留上一次可用的结果,没有白屏。

页面上报错的原文我留了一行:输入错误:字符「a」(ASCII 97)不被 Code A 支持:Code A 仅覆盖 ASCII 0–95。

图 5:Code A 下输入 abc-123,顶部红色报错,徽章变 7 / 8,下方仍保留上一次合法条码

边界也如实写清楚。

第一,页面把终止符那一行的码值显示成 107,标准表里终止符的下标其实是 106,这是显示层的写法,位图用的还是表里第 107 项那个 13 模块图案,不影响编码和解码。

第二,这个页面不中途切换字符集,真实扫码器允许一段条码里换字符集,这里每种输入只能从头到尾用一种。

第三,零售包装上那套一维码是另一门算法,条空宽度不来自这张表;这一页做的是 Code128,常见于物流标签和内部编码。

第四,页面里的「条码总宽度」只算了静区和模块,没算印刷放大系数和条码上下留白,做标签时还要另外留位置。

九、直接下载试玩

这个 Demo 已经完整开源,源代码、本文档、五张截图都在公开仓库里。

把 index.html 下载到本地,用浏览器打开就能改编号、换字符集,看着条码和校验位一起变。

十、本地复现与下一步

本地跑也就两步。

git clone https://atomgit.com/deli007/demo_park.git
cd demo_park\codearts-barcode-generator
python -m http.server 8080

浏览器打开 http://localhost:8080/index.html,改编号、切字符集、把模块宽度从 2 像素调到 4 像素,条码总宽度会从 242 像素变成 484 像素。

下一步我打算做两件事:一是把字符集中途切换补上,看字母加数字的混合内容能省下多少模块;二是拿一台真机扫码枪把页面生成的条码扫一遍,把「算得对」换成「读得出」。

十一、使用码道体会

这次最省事的地方,是我把 107 项图案表直接塞进了需求。

上一轮类似的编码题里,模型会花很长篇幅去回忆一张表,最后还回忆错;这次表是给定的,它只要把逻辑写对。

第二件省事的是自检。我要求它把自检条数显示在页面上,读数和写文章时能直接引用,不用我另做一遍人工核对。

真正需要我补的是边界的说法。第一版没提零售包装用的是另一套编码,这种话不写,读者拿着页面去解释商品上的条码就会讲错。

这类页面别当成扫码器用,它算的是规则,不是识读。