条形码

前言

昨晚在火车上看到了《编码》这本书里面对条形码的介绍,感觉还是比较有意思的,在这里以博文的形式介绍给大家。

正文

现实生活中,二进制数的表现形式就是无所不在的通用产品代码(UPC,Universal Product Code),这个小条形码出现在差不多我们日常所购买的所有商品的包装上。UPC已经成为计算机逐步进入人们日常生活的标志之一。
使用它的初衷仅仅是为了实现零售业的结算和存货管理的自动化,而且他在这方面的应用也很成功。当UPC与一个设计精巧的结账系统结合使用时,顾客会得到一张逐项开列的消费清单,这点是传统的现金出纳员所无法做到的。
有趣的是,UPC也是二进制码,尽管乍看起来她并不太像。将UPC解码并看看UPC到底是怎样工作的,就明白了。
在最常见的形式中,UPC是由30条不同宽度的垂直黑色条纹组成的,它们的间隔宽度也不同,条纹下面标有数字。例如,以下是Campbell公式出品的10 3/4 盎司的罐装鸡汁面汤包上的UPC。
在这里插入图片描述

我们要试着将条形码形象地看成是细条和黑条、窄间隙和宽间隙的排列,事实上,这就是观察条形码的一种方式。在UPC中,黑色条纹有四种不同的宽度,宽条纹的宽度分别是最细条纹宽度的两倍、三倍或四倍。同样,宽间隙的宽度分别是最窄间隙宽度的两倍、三倍或四倍。
但是,另一种解读UPC的方式就是将它们看做一列比特位。记住整个条形码不是在收银台的扫描仪“看到”的那样。扫描仪所读到的并不是下面一排数字,因为这需要更精密的光学识别(OCR,Optical Character Recognition)技术。扫描仪只识别这个条形码的一条窄带,条形码做得很大是为了便于结算台的操作人员用扫描仪对准。扫描仪所看到的哪一个UPC断面可以这样表示:
在这里插入图片描述

看起来与摩尔斯密码很像不是吗?
当计算机从左向右扫描这个信息时,它会首先给遇到的第一个黑条分配一个值为1的比特,给与这个黑条相邻的白色间隙分配一个值为0的比特。随后的条纹和间隙被读作一行中的一些列比特,每个系列的比特可以是1为、2位、3位或4位,而这个位数取决于条纹和空隙的宽度。本例中扫描仪所扫描的条形码与比特位之间的关系可以简单得表示为:
在这里插入图片描述

因此,整个UPC只不过是一串95位二进制数。在本例中,这些比特可以做如下分组。前3位通常都是101,这就是最左边的护线,它帮助计算机扫描仪定位。从护线中,扫描仪可以确定代表单个比特的条和间隙的宽度是多少。否则,所有包装上的UPC就都得采用指定的大小了。
最左边的护线之后是6组比特串,每串含有7个比特位。其中每一组都可以是数字0 ~ 9 的编码,后面我会做一个简短的说明。接下来是一个5比特位的中间护线,这是一个固定的模式(始终是01010),它是内置式的检错码。如果计算机扫描仪没有在应有的位置找到中间护线,它就无法破解UPC码。这条中间护线是用来预防条形码被篡改或被印错的一种方法。

在这里插入图片描述

中间护线后面仍是6组比特串,每组中含有7个比特位。之后是最右边的护线,最右边的护线通常都为101.最右边的护线可以实现UPC的反向扫描,这一点我们将在后面解释。
因此,整个UPC对12个数字进行了编码。UPC的左边含有6个编码数字,每个数字占有7个比特位。你可以利用如下的表格来解码。
在这里插入图片描述

注意,这里每个7位编码都是以0开头,以1结尾的。如果扫面议遇到了一个位于左边的7位编码,这个编码是以1开头以0结尾的,那么它就知道自己没有将UPC正确地读入或者条形码被篡改了。另外我们还注意到每组编码都仅有两组连续为1的比特位,这就暗示每个数字对应着UPC码中的两个垂直条纹。
你也会发现,上表中每组编码都含有奇数个1。这是另一种检查错误和一致性的方法,称为奇偶校验。如果一组比特位中含有偶数个1,它就称为偶校验;如果含有奇数个1,那么它就称为奇校验。这样看来,所有这些编码都拥有奇校验。
破解右边的6组7位编码要用到下表。
在这里插入图片描述

这些编码都是之前编码的补码:之前出现0的地方,现在都换成1,反之亦然。这些编码都是以1开头以0结尾的。除此之外,每组编码都含有偶数个1,属于偶校验。
现在,我们就可以解读UPC了。运用以上两个表格,我们可以确定,Campbell公司的10 3/4盎司罐装鸡汁面汤包上的12个数字为:
0510000125170 \quad 51000 \quad 01251 \quad 7
太令人失望了。就如你所看到的,这与UPC下面所印刷的数字完全相同(这样做事很有意义的,在扫描仪由于某种原因无法解读出条形码时,收银员就可以手动输入这些数字,毫无疑问你也看到过这一幕)。我们没有必要了解解码的全部过程,况且,我们也无法从中解码出任何秘密信息。不过,关于UPC的解码工作已经没有什么可做了,那30根竖条已经变成了12个数字。
第一个数字(这里是0)被称为数字系统符。0意味着这是一个常规的UPC。如果UPC出现在杂货店中那些需要称重的商品上,例如肉、农产品,这个编码就是2。票券的UPC的第一位数字通常是5.
接下来的5个数字表示制造商编码。这种情况下,51000就是Campbell公司的编码。所有Campbell公司的产品都有这个编码。后面的5位代码(01251)是这个公司的某种商品的编码,上例中这个数字就是指10 3/4 盎司罐装鸡汁面。只有和制造商编码同时出现的时候这个编码才有意义。另一个公司的鸡汁面会有另外一个编码,01251在另外一个公司可能是指一种完全不同的产品。
与大家通常的想法相反,UPC不包含物品的价格信息。价格信息可以从商店使用的与该扫描仪相连的计算机中检索到。
最后一个数字(在这里是7)称为模校验字符。这个字符可用来进行另外一种错误校验。为了了解它是如何工作的,我们将前11个数字(在这个例子中是 0 51000 01251)各用一个字母来代替:
ABCDEFGHIJKA \quad BCDEF \quad GHIJK
然后,计算下式的值:

3×(A+C+E+G+I+K)+(B+D+F+H+J)3 \times (A + C + E + G + I + K) + (B + D + F + H + J)

从离这个值最近并且大于或等于它的一个10的整倍数中减去它,其结果称为模校验字符(modulo check character)。在Campbell鸡汁面的例子中,有:

3×(0+1+0+0+2+1)+(5+0+0+1+5)=3×4+11=233 \times (0 + 1 + 0 + 0 + 2 + 1) + (5 + 0 + 0 + 1 + 5) = 3 \times 4 + 11 = 23

紧挨23并且大于或者等于23的10的整数倍是30,因此:

3023=730 - 23 = 7

这就是印在外包装上并以UPC形式编码的模校验字符,这是一种冗余措施。如果扫描仪没有扫描到与计算机计算结果相同的模校验字符,那么计算机就视这个UPC无效。
通常情况下,要表示0 ~ 9 的十进制数字只需要4个比特位就足够了。UPC中每个数字用了7个比特位。这样,UPC总共用了95个比特位来表示11个有效的十进制数。实际上,UPC中还有空白位置(相当于9个0比特),它们位于左、右护线的两侧。这就意味着,整个UPC需要113个比特位来编码11个十进制数,平均每个十进制数所用的比特位超过了10个。
如我们所看到的,有部分冗余对于检错来讲是必要的。这种商品编码如果能够被顾客用笔轻易地改动,那么这种产品编码措施也就没有任何意义了。
UPC可以从两个方向读,这一点是非常方便的。如果扫描装置解码的第一个数是符合偶校验(即7位编码中有偶数个1)的,扫描仪就会知道,它正从右向左扫描UPC码。计算机就会使用如下表来解码:
在这里插入图片描述

以下是对左边数字的解码表:
在这里插入图片描述

所以这些7位编码都是与由左向右扫描时得到的UPC完全不同。这里不会有模棱两可的现象存在。

声明

此博文是对《编码》一书的直接引用,侵删。