大部分檢查功能已經在昨日做完,剩下的就是最重要的檢查碼,現在來討論一下檢查碼如何做吧!(其實已經逃避兩天了 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,%
),如果整除就是合規的格式。
總算完成了,檢查碼比我想像的還要花時間,雖然完成,但是還有很多要優化,就繼續加油吧~