大部分檢查功能已經在昨日做完,剩下的就是最重要的檢查碼,現在來討論一下檢查碼如何做吧!(其實已經逃避兩天了 XD)
Checksum 被稱為核對和(維基百科和國家教育研究院稱為「核對和」),是經過計算後產生的數值,用來檢核前面的值是否正確。像是我們會用 MD5 去把資料加密後,檢查是否正確,或有沒有被串改。而其中一種方法為「校驗碼」(Check digit)。
校驗碼通常為一組字的最後一碼,用來確認前面的資料都是正確的(應該說符合計算規則)。因為前面的值是經過某種計算後,才會產生校驗碼,因此可以用校驗碼快速的審核資料的正確性。身分證的尾碼就是屬於校驗碼,ISBN 最後一碼也是如此。
校驗碼太過文鄒鄒,因此用檢查碼作為代表。身分證的格式為:_英文_數數數數數數數數數,總共十碼(例如:A999999999)。這時需要把英文轉換成數值,然後再套入數學公式計算就可以算出檢查碼。
因此可以參考 Day19 的資料,找到每個代碼對應的數值為何:
| 代碼 | 數值 | 縣市 | 
|---|---|---|
| A | 10 | 臺北市 | 
| B | 11 | 臺中市 | 
| C | 12 | 基隆市 | 
| D | 13 | 臺南市 | 
| E | 14 | 高雄市 | 
| F | 15 | 新北市 | 
| G | 16 | 宜蘭縣 | 
| H | 17 | 桃園市 | 
| I | 34 | 嘉義市 | 
| J | 18 | 新竹縣 | 
| K | 19 | 苗栗縣 | 
| M | 21 | 南投縣 | 
| N | 22 | 彰化縣 | 
| O | 35 | 新竹市 | 
| P | 23 | 雲林縣 | 
| Q | 24 | 嘉義縣 | 
| T | 27 | 屏東縣 | 
| U | 28 | 花蓮縣 | 
| V | 29 | 臺東縣 | 
| W | 32 | 金門縣 | 
| X | 30 | 澎湖縣 | 
| Z | 33 | 連江縣 | 
| L | 20 | 臺中縣 | 
| R | 25 | 臺南縣 | 
| S | 26 | 高雄縣 | 
| Y | 31 | 陽明山管理局 | 
這邊使用維基百科的範例,使用合法(合乎計算規則)的身分證字號「A123456789」當作範例。
這時需要對照上表,把首碼的英文字變成兩個數,所以 A 轉化成 10,再加上後面九碼,就成為一組 11 碼的數值。
| A | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 
接著再把這個數值,依序乘上 1、9、8、7、6、5、4、3、2、1、1,然後再相加:
1*1 + 0*9 + 1*8 + 2*7 + 3*6 + 4*5 + 5*4 + 6*3 + 7*2 + 8*1 + 9*1 = 130
這組數字的總和為 130。
如果把它加上表,會更清楚:
| 證號 | A | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 數值 | 1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 
| 乘數 | 1 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 1 | 
取得加總後的值後,除以 10 取得餘數,當餘數為 0 時(也就是餘除 10 是為 0),表示這組身分證字號為合規的。
130 % 10 = 0
檢查碼的功能命名為 checkCkDigit() ,裡面包含轉換英文、數字加總、是否整除等三大部分。
function checkCkDigit(code) {
  const placeCode = checkPlace(code.substring(0, 1)); // 取得首碼的數值
  const bodyCode = code.substring(1, 9); //取得中間非驗證碼的數值
  const lastCode = code.substring(8); //取得尾碼
  const idSum = calHead(placeCode) + calBody(bodyCode) + parseInt(lastCode) * 1; //計算總和 //尾數的*1 其實可以不用乘
  const modResult = idSum % 10;
  const result = modResult === 0;
  console.log(
    `sum = ${idSum}, mod result = ${modResult}, check result = ${result}`
  );
  return result;
}
function calBody(code) {
  let sum = 0;
  for (let i = 0; i < code.length; i++) {
    sum += parseInt(code[i]) * (8 - i);
  }
  console.log(`body sum = ${sum}`);
  return sum;
}
function calHead(code) {
  let sum = parseInt(code[0]) * 1 + parseInt(code[1]) * 9;
  console.log(`head sum = ${sum}`);
  return sum;
}
其中需要增加 calHead 和 calBody,用來計算首碼,和後面八碼數字,由於最後的驗證碼是一位數,並且直接乘與 1,因此就直接放在算式中。
最後再把總合,進行模除(mode,%),如果整除就是合規的格式。
總算完成了,檢查碼比我想像的還要花時間,雖然完成,但是還有很多要優化,就繼續加油吧~