表單提示身分證號無效、自己卻確定沒填錯;或者寫校驗時想知道到底該信哪一層。這兩種情況都要回到那一位校驗碼:它是前 17 位算出來的,末尾那個 X 也只是同一個演算法的結果。整條鏈路只有三步——加權、求和、取餘查表。
18 位號碼的結構
前 6 位是地址碼,接著 8 位是出生日期,再 3 位順序碼(同一天同一區域內的排列,末位奇偶區分性別),最後 1 位是校驗碼。前 17 位攜帶全部身分資訊,第 18 位什麼都不攜帶,它只負責一件事:讓前面 17 位可以被算術驗證。
三步算出校驗位
- 前 17 位逐位乘以權重 7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2,再把 17 個乘積相加。
- 用這個和對 11 取餘,餘數落在 0 到 10 之間。
- 按餘數查表得到校驗位:0 到 10 依次對應 1,0,X,9,8,7,6,5,4,3,2。
拿一個公開的示範號段走一遍:前 17 位 11010519491231002,加權求和得 167,167 除以 11 餘 2,查表得到 X,完整號碼就是 11010519491231002X。
| 位序 | 數字 | 權重 | 乘積 |
|---|---|---|---|
| 1 | 1 | 7 | 7 |
| 2 | 1 | 9 | 9 |
| 3 | 0 | 10 | 0 |
| 4 | 1 | 5 | 5 |
| 5 | 0 | 8 | 0 |
| 6 | 5 | 4 | 20 |
| 7 | 1 | 2 | 2 |
| 8 | 9 | 1 | 9 |
| 9 | 4 | 6 | 24 |
| 10 | 9 | 3 | 27 |
| 11 | 1 | 7 | 7 |
| 12 | 2 | 9 | 18 |
| 13 | 3 | 10 | 30 |
| 14 | 1 | 5 | 5 |
| 15 | 0 | 8 | 0 |
| 16 | 0 | 4 | 0 |
| 17 | 2 | 2 | 4 |
右列 17 個乘積相加:7+9+0+5+0+20+2+9+24+27+7+18+30+5+0+0+4 = 167。這張表也是最好用的核對載體——自己算一遍如果對不上 167,就是某一位的權重抄錯了。
權重不是隨手定的
那串 7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2 是 2 的次方取模的產物:第 i 位(從 1 數起)的權重等於 2 的 (18−i) 次方對 11 取餘。逐位推一遍能全部對上——2 的 17 次方模 11 得 7,2 的 16 次方得 9,2 的 15 次方得 10,一路降到 2 的 1 次方得 2。查表那一步同樣有出處:餘數 r 對應的校驗值就是 (12 − r) 對 11 取餘,r 為 2 時算出 10,而 10 只能寫成 X。
X 不是留給誰的特殊標記
按公式,餘數為 2 的這一檔算出來的校驗值是 10。號碼要求每一位都是單一字元,而 10 是兩位,就用羅馬數字 X 頂替佔這一格。所以末位是 X 只說明前 17 位的加權和恰好模 11 餘 2,與出生日期、登記地區都沒有關係,更不是什麼特殊身分的標識。
它能發現什麼、發現不了什麼
2 的任何次方對 11 取餘都落在 1 到 10 之間,永遠不為 0——餘數序列是 2,4,8,5,10,9,7,3,6,1,然後回到 2,週期為 10。把某一位從 d 改成 e,加權和的變化量是 (e−d) 乘以該位權重;要讓改動察覺不到,這個乘積就得是 11 的倍數,而 |e−d| 最大只有 9,權重本身又不是 11 的倍數,湊不出來。我把 17 個位置上所有可能的單字元改動枚舉了一遍:每個位置有 9 種別的數字可填,共 153 種,改完之後校驗位仍等於原值 X 的有 0 種。所以「一次手滑逃掉」不是機率小,是不可能。
它管不到的是換位。權重表以 10 為週期,第 1 位與第 11 位同為 7、第 2 位與第 12 位同為 9,這樣一路到第 7 位與第 17 位同為 2,共七對。數字落在這七對位置裡互相調換時,加權和完全不變,校驗位照樣對得上。這是所有單校驗位方案共同的上限,不是實作寫錯了。
它還保證不了算術之外的任何事:隨機拼一串 18 位數字,校驗位恰好碰對的機率是十一分之一。固定隨機種子跑 200000 組隨機前 17 位,末位等於 X 的有 18063 組,佔 9.03%,與理論值 9.09% 差 0.06 個百分點。也就是說它擋手滑很有效,擋編造幾乎沒有作用,更不能證明這個號碼對應一個真實存在的人。
15 位舊號碼怎麼變成 18 位
出生年月日從 6 位(YYMMDD)擴到 8 位(YYYYMMDD)時,年份前補上世紀碼,末尾再加一位校驗。示範號去掉世紀寫法是 110105491231002,把 49 補成 1949 之後前 17 位就是 11010519491231002,按三步算出 X,完整的 18 位得到 11010519491231002X。反向做也成立:刪掉校驗位、再把年份的世紀碼去掉,就還原成 15 位寫法。處理歷史資料時這一段最容易被漏,因為 15 位號碼根本沒有校驗位可查。
工程上分幾層來做
輸入框裡的即時校驗跑到校驗位這一層就夠,它攔得住打錯的;需要更硬的確認,就得走實名核驗那類通道,兩層的成本和能給出的結論完全不同。展示的時候它屬於敏感欄位,列表裡要能辨認又不能整串露出,隱私資訊遮蔽 處理的就是這類需求。想看同一個思路在別的號碼上怎麼落地,銀行卡校驗工具 用的是另一套加權取模規則,權重不同但結構一致;要逐位核對本站這串權重,身分證號碼校驗 會把加權和、餘數與查表結果一併列出來。
Q:改一位能發現,改兩位為什麼就不一定
單字元改動會改變加權和,而權重的選取讓這種改動很難落回同一個餘數。同時改兩位時,如果兩處帶來的差值互相抵消,和沒變、餘數沒變,校驗位就對得上了。這是所有單校驗位方案共同的上限,不是實作寫錯了。
Q:地址碼和出生日期它不管嗎
校驗位只看整串 17 位的加權和,不判斷 6 位區劃碼是否真實存在,也不判斷日期是否合法、是否為閏年。完整的格式校驗通常還要補一層出生日期範圍檢查,那是另外一段獨立的邏輯。
Q:X 大寫小寫都行嗎
規則裡是 X。多數系統會在輸入時容忍小寫再轉大寫,但儲存和比對最好統一成一種寫法,否則同一個號碼會因為大小寫差異被判成兩筆不同記錄。