為什么超市售貨員掃一下條形碼就能結(jié)賬?為什么別人掃一下你的二維碼就能加上你的微信?小小的條形碼、二維碼中究竟如何蘊(yùn)藏如此多不同的信息?今天,就讓我們和孩子們一起走進(jìn)條形碼、二維碼的世界吧!

撰文 | 吳進(jìn)遠(yuǎn)
我們前一篇文章討論了摩爾斯電碼,談到它對(duì)當(dāng)代的計(jì)算機(jī)技術(shù)有著深刻的影響。這種影響并不是在具體的編碼方法上,而主要是體現(xiàn)在思維方法上。現(xiàn)在我們購買到的大多數(shù)商品,包裝上面都有條形碼。條形碼初期存在多個(gè)發(fā)明,現(xiàn)在也存在非常多的變種。條形碼可以算是和摩爾斯電碼沾點(diǎn)邊,因?yàn)樵缙诘囊晃话l(fā)明家曾經(jīng)受到過摩爾斯電碼的啟示。確實(shí),從某種意義上說,我們可以想象把摩爾斯電碼的點(diǎn)和劃,垂直畫成線,變成窄和寬的條紋。當(dāng)然現(xiàn)在主流應(yīng)用上的條形碼,并不是簡單地從摩爾斯電碼轉(zhuǎn)換來的。條形碼世界
今天,計(jì)算機(jī)越來越多地參與著我們生活的方方面面。為了把信息迅速方便地送入計(jì)算機(jī),人們設(shè)計(jì)了各種各樣的編碼,條形碼就是其中的一種。其他的編碼方法,比如RFID,盡管成本越來越低,但相比之下,條形碼仍然是最便宜的,其成本幾乎為零,因?yàn)闂l形碼只需要用油墨印在包裝盒上即可。條形碼是怎樣將信息編碼的呢?對(duì)于不同的應(yīng)用存在許多標(biāo)準(zhǔn)。我們這里介紹一下其中一個(gè)標(biāo)準(zhǔn),即GTIN-13以及它所對(duì)應(yīng)的條形碼編碼標(biāo)準(zhǔn)EAN-13。GTIN是Global TradeItem Number的意思,其中的GTIN-13標(biāo)準(zhǔn)是用13位數(shù)字代表全球貿(mào)易中的萬物。其中最高的三位代表生產(chǎn)物品的國家,比如中國生產(chǎn)的產(chǎn)品前三位是690-695。其余一些位數(shù)表示地域,行業(yè)等信息,靠后的一些位數(shù)是物品的代碼。如果13位數(shù)全部用滿,可以表述10萬億種不同的物品,足夠全球所有人每人研發(fā)1000種不同的商品。我們現(xiàn)在在市場上買到的商品,大部分都有這樣一個(gè)13位數(shù)的代碼。GTIN兼容了國際標(biāo)準(zhǔn)書號(hào)(ISBN),國際標(biāo)準(zhǔn)期刊序號(hào)(ISSN)等等。當(dāng)GTIN-13需要印刷成條形碼的時(shí)候,使用的是EAN-13條形碼標(biāo)準(zhǔn)。比如作者參與寫作的一本科學(xué)普及書的條形碼,如下圖所示。對(duì)于圖書,不管是哪個(gè)國家出版的,其前三位都被指定為978或979。而雜志期刊等,前三位總是977。
大家可以仔細(xì)觀察上面的條形碼,我們可以看到數(shù)字5出現(xiàn)了幾次,不過它們似乎長的不完全一樣,在左邊的兩個(gè)是一個(gè)樣,而在右邊的兩個(gè)顯然不同。如果認(rèn)真看看,左邊與右邊條紋是“黑白顛倒”的關(guān)系。可是,再看看左邊出現(xiàn)的兩個(gè)7,它們似乎也不一樣。此外,在條形碼左邊與右邊各有6位數(shù)字,這并不難理解,但整個(gè)碼符號(hào)的最左邊那個(gè)9是怎么來的?難道可以無中生有嗎?
為此,我們需要了解一下EAN-13(包括ISBN,ISSN,UPC等)條形碼的生成規(guī)則。條形碼的編碼規(guī)則
EAN-13條形碼是用兩個(gè)條紋來表示一個(gè)數(shù)字的,整個(gè)碼包括13個(gè)數(shù)字,其中直接編碼12個(gè),左邊6個(gè)右邊6個(gè),第13個(gè)用后面介紹的方法隱含編碼。條形碼兩邊與中間安排了起始符(S)中間符(M)以及結(jié)束符(E),各為兩個(gè)窄條。因此,所有碼,不管具體數(shù)字是什么,都包含有30個(gè)條紋。那么,每個(gè)數(shù)字又是怎樣用兩個(gè)條紋表示的呢?這就需要我們在更細(xì)尺度上討論。每個(gè)數(shù)字的兩個(gè)條紋,包括了兩黑兩白四個(gè)區(qū)域,它們的總寬度為7個(gè)單位寬度。這個(gè)單位寬度可以根據(jù)印刷精度自由選擇,比如當(dāng)我們把單位寬度選定為0.5毫米時(shí),每個(gè)數(shù)字所占寬度為3.5毫米。對(duì)于左邊6個(gè)數(shù)字,每個(gè)數(shù)字的左邊一定是白的,而右邊一定是黑的。每個(gè)數(shù)字從左到右都是“白黑白黑”地構(gòu)造。這樣,當(dāng)幾個(gè)數(shù)字一個(gè)個(gè)緊挨在一起的時(shí)候,它們之間就可以存在一個(gè)清晰的邊界。了解了這些,我們就可以想象自己是當(dāng)年制定這種條形碼的設(shè)計(jì)師,很容易地?cái)?shù)一數(shù)可用的編碼有哪些。我們可以把7個(gè)單位寬度組合在一起,看成7個(gè)比特的二進(jìn)制數(shù)。如果這7個(gè)比特可以任意安排黑白,則可以表達(dá)128個(gè)字符。不過我們已經(jīng)限定最左邊一定是白色,最右邊一定是黑色,這樣就只有中間5個(gè)比特可以改變,或者說最多可以表達(dá)32個(gè)字符。把這32個(gè)可能的字符全部畫出來,就得到下面這個(gè)圖。
現(xiàn)在,我們把不符合“白黑白黑”要求的字符去掉,還剩下20個(gè)可用的字符。這20個(gè)字符又可以分成兩類,一類包含有奇數(shù)個(gè)(3個(gè)或5個(gè))單位寬度為黑,共10個(gè),另一類包含有偶數(shù)個(gè)(2個(gè)或4個(gè))單位寬度為黑,也是共有10個(gè)。我們把這兩類字符分別用來作為0-9數(shù)字的代碼。其中奇偶性為奇的10個(gè)稱為EAN-L碼,在上面圖中用淺棕色標(biāo)注。奇偶性為偶地10個(gè)稱為EAN-G碼,在上面圖中用淺綠色標(biāo)注。這兩種左邊的條形碼如下圖所示。
那么,右邊的條形碼又是什么樣的呢?我們希望最終的條形碼具有一定的對(duì)稱性,比如希望右邊的碼左黑右白,這樣可以與結(jié)束符(E)有一個(gè)清晰的邊界。因此最簡單的一個(gè)做法,是把EAN-L碼黑白顛倒,這樣我們就有了EAN-R碼,如下圖所示。顯然,由于EAN-L的奇偶性為奇,因此很容易看出EAN-R的奇偶性為偶,里面黑條的總寬度為偶數(shù)個(gè)單位寬度,與EAN-L正好反過來。

有了左邊與右邊數(shù)字的條形編碼圖形,我們就很容易拼接出一個(gè)完整的條形碼。當(dāng)我們只需要編碼12個(gè)數(shù)字時(shí),也就是說當(dāng)13位數(shù)中最高位為0時(shí),左邊6個(gè)數(shù)字都用EAN-L碼,右邊6個(gè)數(shù)字則用EAN-R碼。把數(shù)字與S,M,E符拼接在一起后,我們就可以得到如下圖所示的條形碼。

我們前面問過一個(gè)問題,在13位編碼的整個(gè)條形碼碼符號(hào)的最左邊那個(gè)數(shù)字(我們前面圖書的條形碼中的9)是怎么來的。此外,大家還會(huì)問,我們前面談到的EAN-G圖形能不能用在條形碼的左邊,代替EAN-L碼?實(shí)際上,這兩個(gè)問題是聯(lián)系在一起的,EAN-13中,最左邊那個(gè)數(shù)字,就是利用EAN-G圖形,代替左邊6個(gè)數(shù)字中一部分EAN-L圖形來表述的。
在條碼左邊6個(gè)數(shù)字中,每個(gè)數(shù)字可以選用L或者G兩種碼。因此通過選擇每一位的L或G,一共可以得到64(2的6次方)種組合。人們從這64種組合中,挑出了10個(gè)組合,用來表述13位編碼中的最左邊那個(gè)數(shù)。這10個(gè)組合以及它們代表的數(shù)字為:0=LLLLLL;1=LLGLGG;2=LLGGLG;3=LLGGGL;4=LGLLGG;5=LGGLLG;6=LGGGLL;7=LGLGLG;8=LGLGGL;9=LGGLGL。這樣一來,最左邊這個(gè)數(shù)不需要直接用一個(gè)單獨(dú)的圖形表述,而只需要通過選配左邊6個(gè)數(shù)字編碼圖形的L或G組來“隱喻”。現(xiàn)在我們再回過頭看我們前面那本書的條形碼,原來的一些疑問也就豁然開朗了。
首先,右邊的兩個(gè)5與左邊的兩個(gè)5自然不會(huì)是相同的,我們知道 EAN-L 與 EAN-R 對(duì)應(yīng)的10個(gè)編碼,是黑白反轉(zhuǎn)的關(guān)系。那么,同在左邊的相同數(shù)字編碼一樣嗎?不一定。比如上面條碼中左邊的兩個(gè)7,它們一個(gè)是 L 碼另一個(gè)是 G 碼。因?yàn)檫@個(gè)條碼編碼了第13位數(shù)字9,因此左邊6個(gè)數(shù)字的L或G的選擇為9=LGGLGL,因此它的第一個(gè)7是L而第二個(gè)7是G,所以這兩個(gè)7長得不一樣。此外,我們還可以看出左邊的兩個(gè)5恰好都是L,否則它們也未必相同。
條形碼帶給我們的啟示
在很多編碼工作的實(shí)踐中,我們的著眼點(diǎn)是提高編碼的效率。也就是說,利用盡量少的資源來存儲(chǔ)或者傳輸比較多的信息。但是在設(shè)計(jì)條形碼的時(shí)候,更需要考慮的,是可靠性和準(zhǔn)確性。為此,我們可能會(huì)“浪費(fèi)”一些編碼資源,來提高編碼的冗余度。在前面談到的條形碼中,每個(gè)數(shù)字的編碼空間有7個(gè)單位寬度,如果充分利用可以編制128個(gè)字符。但是我們對(duì)編碼空間作了限制:(1)左白右黑,(2)包含兩個(gè)條紋。這樣一來,這個(gè)編碼空間中就只剩下20個(gè)可以用的組合了。但是這樣做帶來的好處非常多。首先是兩個(gè)數(shù)字挨在一起,它們之間存在一個(gè)黑白清晰的邊界。同時(shí)在每個(gè)數(shù)字的編碼空間中,也不會(huì)出現(xiàn)一大片黑,或者一大片白的狀況,而是存在足夠的黑白變化,便于掃描器辨別。更重要的是,這樣的編碼方法提供了很多簡便的查錯(cuò)方法。比如一個(gè)完整的條形碼,不論是什么內(nèi)容,總是包含30個(gè)條紋。這樣,當(dāng)掃碼器掃過之后如果發(fā)現(xiàn)多于30或少于30個(gè)條紋,立即就能知道是出錯(cuò)了。條形碼應(yīng)用中,還會(huì)出現(xiàn)一個(gè)常見的復(fù)雜性,就是掃碼器既可能從左向右正著掃,也可能反過來掃。這就要求條形碼自身攜帶左右標(biāo)識(shí)。當(dāng)我們在條形碼的左邊使用EAN-L碼,右邊使用EAN-R碼的時(shí)候,條形碼的左右就非常分明。左邊所有數(shù)字的奇偶性為奇,右邊所有數(shù)字的奇偶性為偶。當(dāng)我們需要編制13位數(shù)編碼,因此在左邊6個(gè)數(shù)中有些會(huì)使用EAN-G碼的時(shí)候,左邊有些數(shù)字的奇偶性也可能呈現(xiàn)偶。不過,我們前面看到,左邊6個(gè)數(shù)中最左邊那一位總是使用L碼,這就足以作為條形碼的左標(biāo)識(shí)了。從條形碼到二維碼
條形碼毫無疑問是非常成功的,但由于條形碼是編碼空間是一維的,因此可以攜帶的信息非常有限。很自然,人們想到要向平面上兩個(gè)維度發(fā)展。多年來,二維的條形碼出現(xiàn)過許多標(biāo)準(zhǔn)及變化。我們今天經(jīng)??吹降囊环N是QR碼。下圖所示QR碼是作者創(chuàng)作的一個(gè)科學(xué)普及音樂視頻文件在微云上的鏈接。
這里特意提醒一下讀者,一個(gè)二維碼當(dāng)中,直接編碼的內(nèi)容是幾十乃至上百個(gè)字母或數(shù)字,它們通常構(gòu)成一個(gè)鏈接,但它們不是視頻文件本身。視頻文件往往會(huì)需要幾十 MB 乃至幾十 GB 存儲(chǔ)空間,二維碼存儲(chǔ)不了那么多的數(shù)據(jù)。
當(dāng)然,二維碼要容納幾十乃至上百個(gè)字母和數(shù)字也并不容易。對(duì)比條形碼,人們對(duì)二維碼在可靠性和準(zhǔn)確性上的要求是一樣的。但是,二維碼要比條形碼容納更多的信息,因此還必須兼顧編碼的效率。這兩項(xiàng)要求在有的情況下是矛盾的,但是在很多時(shí)候二者是相輔相成的。二維碼掃碼使用時(shí)通常是用手機(jī)來拍照,在手機(jī)內(nèi)得到一個(gè)由像素構(gòu)成的二維點(diǎn)陣。手機(jī)中的軟件只有可靠準(zhǔn)確地獲得了二維碼的高度寬度等外形參數(shù),才能正確地讀取編制在二維碼中的數(shù)據(jù)。那么,怎樣才能方便地獲取二維碼的外形參數(shù)呢?這就需要我們在設(shè)計(jì)時(shí)作出仔細(xì)的考慮。從QR碼上,可以看到在左上角,右上角和左下角各有一個(gè)口字形或回字形的方塊。我們應(yīng)該可以猜測出,這三個(gè)方塊就是為了提供二維碼外形參數(shù)的。問題是,為什么需要三個(gè)方塊呢?只在左上角上留一個(gè)方塊行不行?我們知道手機(jī)的照相機(jī)照出來的照片是會(huì)發(fā)生形變的,如果只有一個(gè)方塊,就很不容易獲取二維碼的高度和寬度這兩個(gè)參數(shù)。如果只留兩個(gè)方塊,比如,保留右上角和左下角這兩個(gè)方塊。這好像也不行,因?yàn)樵谑謾C(jī)的照片中,軟件無法去辨認(rèn)哪邊是上哪邊是下。如果只保留左上角和右上角兩個(gè)方塊,則上下倒是可以區(qū)分出來了。但是由于手機(jī)照片的形變,我們只能得到二維碼寬度這個(gè)參數(shù),而很難得到高度這個(gè)參數(shù)。因此,我們現(xiàn)在看到的二維碼里面有三個(gè)大方塊。我們這里談到的僅僅是一些最基本的考慮,實(shí)際上二維碼里的學(xué)問還是不少的,這里有一個(gè)問題提供給大家思考。下面這個(gè)二維碼中,只包含了一個(gè)字母“a”。既然只有一個(gè)字母,那么這個(gè)字母占據(jù)的面積應(yīng)該是很小的吧?因此在整個(gè)碼所占的面積中,應(yīng)該大部分是空白。但是,我們并沒有在上面這個(gè)二維碼中看到大塊的白色或黑色區(qū)域,而是到處都是錯(cuò)落有致,黑白相間。大家不妨想想為什么要這樣設(shè)計(jì)?用什么辦法可以做到這點(diǎn)?
孩子們在世間遇到的問題從來不會(huì)按照教科書的次序,先易后難。他們可能還沒有學(xué)過二進(jìn)制,但卻可能在任何時(shí)候找到一個(gè)條形碼或者二維碼來問家長。怎樣才能不被孩子問住呢?很簡單,和孩子一塊找一堆條形碼或二維碼一塊研究研究,找找規(guī)律,再上網(wǎng)查查,定會(huì)有所收獲。· 滴!刷卡的時(shí)候發(fā)生了什么?| 親子科學(xué)系列(8)
· 肥皂泡,光盤上的彩色和彩虹是一回事嗎?| 親子科學(xué)系列(7)
· 學(xué)文還是學(xué)理?所有的知識(shí)都不會(huì)白學(xué) | 親子科學(xué)系列(6)
· 爬門框、拆車輪,玩也是一種學(xué)習(xí)方式 | 親子科學(xué)系列(5)
· 被海淀家長碾壓?多和孩子一起讀無字之書 | 親子科學(xué)系列(4)
· 切薯格、拆門鎖,生活中的冷知識(shí)也有講究 | 親子科學(xué)系列(3)
· 玩手機(jī),學(xué)會(huì)考試需要的硬核知識(shí) | 親子科學(xué)系列(2)
· 帶娃漫步荷塘邊,有月色,還可談科學(xué) | 親子科學(xué)系列(1)