0%

JS 筆記 - 信用卡驗證

credit card

在一般消費平台會需要刷卡,並要填入信用卡單,再填寫第一欄的時候會發現卡片會自己辨識是屬於哪類的信用卡,有 Master Card,VISA,JCB,美國運通卡號只有 15 碼,不再這次驗證範圍。這次剛好在課程中學到信用卡驗證器,就來依照條件實作看看吧!

信用卡號產生器

可自行輸入信用卡 16 碼,或是用產生器

信用卡驗證流程

  1. 從左邊算起來的第一個數字為發卡行,Master Card 是 5 開頭,Visa 是 4,JCB 則是 3。
  2. 前 15 位數經過加權後加總,會得出一個數字,先把這數字除以 10 取餘數,如果結果是 0,那檢查碼就是 0,否則就是用 10 減去之後的結果。
  3. 權重的部分你可以這樣記:
    • 左邊數起奇數位是 *2
    • 偶數位是 *1
    • 若是在計算的過程中某一位數加權後的結果比 10 大,那請減去 9。

      舉例來說,5412-3456-7890-1232 這個卡號的第一位是 5,代表這是 MasterCard 的卡。

奇數位加總

  • 奇數位加總為:5*2 + 1*2 + 3*2 + 5*2 + 7*2 + 9*2 + 1*2 + 3*2,原本應該是:10 + 2 + 6 + 10 + 14 + 18 + 2 + 6。
  • 前面有說過「如果比 10 大,請減去 9」,所以就是 1(10-9) + 2 + 6 + 1(10-9) + 5(14-9) + 9(18-9) + 2 + 6 = 32。

偶數位加總

  • 偶數位加總為:4 + 2 + 4 + 6 + 8 + 0 + 2 = 26,乘以 1 之後還是 26。

    第 16 碼檢查碼,不用算進偶數列。

卡片是否可用

把 32 跟 26 相加,得到 58,58 % 10 = 8,因此檢查碼就是 10-8 = 2,而卡號的第 16 碼也是 2,因此這個卡號是沒有問題的。

任務需求

輸入信用卡號

輸入為一個信用卡卡號,皆為 16 碼,每 4 碼以 - 做為分隔。
EX. 5412-3456-7890-1232

輸出

若是信用卡不合法,請輸出 INVALID,合法則輸出信用卡的發卡行,只會有 VISA 與 MASTER CARD 兩種結果。

實作信用卡驗證架構

所使用的卡號為 5412-3456-7890-1232
首先,觀察到信用卡號中間的 dash 符號,在計算時是不需要出現的。
所以可以先給一個變數存卡片號碼,並使用 replace 方法把 dash 的內容拿掉,這樣之後才能加總。

1
2
3
let cardNum = "5412-3456-7890-1232";
let newCardNum = cardNum.replace("5412-3456-7890-1232", "5412345678901232");
console.log(newCardNum); //5412345678901232

奇偶數加總、取出奇偶數

1
2
3
4
5
6
7
8
//奇偶數相加
let sum = evenNum(newCardNum) + oddNum(newCardNum);

//偶數位加總
function evenNum(newCardNum) {}

//奇數位加總
function oddNum(newCardNum) {}

加權後的數字

題目有提到,前 15 位數經過加權後加總,會得出一個數字,先把這數字除以 10 取餘數,如果結果是 0,那檢查碼就是 0,否則就是用 10 減去之後的結果,這一段文字可以先改成步驟來寫。

  1. resultNum = sum % 10;
  2. 如果 resultNum = 0;
  3. 檢查碼 = resultNum;
  4. 否則就是 resultNum = 10-resultNum;

可是步驟這樣寫有點難變成虛擬碼,可以換個角度來想,

  1. resultNum = sum % 10;
  2. 如果 resultNum !=0;
  3. resultNum = 10-resultNum;

這樣就可以試著改成程式碼,

1
2
3
4
let resultNum = sum % 10;
if (resultNum != 0) {
resultNum = 10 - resultNum;
}

判斷驗證是否成功架構

  1. 第 16 碼是檢查碼,如果與檢查碼不符,就是 INVALID。
  2. 如果第一碼是 5 就是 MASTER CARD,不然就是 VISA,為什麼沒有 JCB,因為這次任務只需要這兩種卡片。
1
2
3
4
5
6
7
8
9
if (resultNum !== newCardNum[15] * 1) {
console.log("INVALID");
} else {
if (card[0] === "5") {
console.log("MASTER CARD");
} else {
console.log("VISA");
}
}

目前 console 出來的結果會是 INVALID,因為還沒奇偶數的運算。

截至目前為止的架構已經寫好,不明確的地方都用函式填空法完成,完整程式碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
let cardNum = "5412-3456-7890-1232";
let newCardNum = cardNum.replace("5412-3456-7890-1232", "5412345678901232");

let sum = evenNum(newCardNum) + oddNum(newCardNum);
let resultNum = sum % 10;
if (resultNum != 0) {
resultNum = 10 - resultNum;
}

if (resultNum !== newCardNum[15] * 1) {
console.log("INVALID");
} else {
if (card[0] === "5") {
console.log("Master Card");
} else {
console.log("VISA");
}
}
//偶數位加總
function evenNum(newCardNum) {}

//奇數位加總
function oddNum(newCardNum) {}

if (resultNum !== newCardNum[15] * 1)if (resultNum !== Number(newCardNum[15]) ) 都是把字串轉成數字的方式。

奇偶數列運算實作

目前得到的卡號: 5412345678901232

先做簡單的偶數列

  1. 因為偶數位比較單純,所以先來做偶數位,觀察數列,偶數位從第 1 個開始。(程式式從第 0 位開始)。
  2. 看到要取順序,就要想到用 for 迴圈,並且偶數最末位為第 14 個,數列為第 13 個。
  3. 因為要跳兩位取得數字,故要 i+=2。
1
2
3
4
5
6
7
8
9
function evenNum(newCardNum) {
let sum = 0;
for (let i = 1; i <= 13; i += 2) {
let resultNum = Number(newCardNum[i]);
sum += resultNum;
console.log(sum); //4 2 4 6 8 0 2
}
return sum;
}

步驟說明:

  1. 先設定偶數數列總數 sum 起始為 0。
  2. 並且數列長度小於等於 13 個數列,並透過 i+=2 取得偶數列的數字。
  3. sum 會依序跑 newCardNum 的每個數字,跑到偶數列就存到 sum 的變數中。
  4. 確認 console 結果為預期。
  5. 回傳到 sum。

奇數列加總實作

  1. 與偶數列方法雷同,所以把偶數函式中的方法先複製到奇數列的函式內。
  2. 奇數列從第 0 個開始,最後一碼是第 15 個。
1
2
3
4
5
6
7
8
function oddNum(newCardNum) {
let sum = 0;
for (let i = 0; i <= 15; i += 2) {
sum = Number(newCardNum[i]);
console.log(sum); // 5 1 3 5 7 9 1 3
}
return sum;
}
  • 題目有提到奇數列有加權重(數字*2),大於 10 的話要減 9,這邊的程式碼要加上運算。
  • 把運算結果回傳給 sum。
1
2
3
4
5
6
7
8
9
10
11
function oddNum(newCardNum) {
let sum = 0;
for (let i = 0; i <= 15; i += 2) {
let resultNum = Number(newCardNum[i]);
if (resultNum >= 10) {
resultNum -= 9;
}
sum += resultNum;
}
return sum;
}

驗證一下 sum 的結果

驗證結果如下,是如預期的結果。

1
2
3
4
let sum = evenNum(newCardNum) + oddNum(newCardNum);
console.log(evenNum(newCardNum)); //26
console.log(oddNum(newCardNum)); //32
console.log(sum); //58

最終答案會是 MASTER CARD。

完整程式碼與 Demo

DEMO: https://codepen.io/hnzxewqw/pen/LYbVjpN?editors=1111

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
let cardNum = "5412-3456-7890-1232";
let newCardNum = cardNum.replace("5412-3456-7890-1232", "5412345678901232");
let sum = evenNum(newCardNum) + oddNum(newCardNum);
let resultNum = sum % 10;
if (resultNum != 0) {
resultNum = 10 - resultNum;
}

if (resultNum !== newCardNum[15] * 1) {
console.log("INVALID");
} else {
if (newCardNum[0] === "5") {
console.log("MASTER CARD");
} else {
console.log("VISA");
}
}
//偶數位加總
function evenNum(newCardNum) {
let sum = 0;
for (let i = 1; i <= 13; i += 2) {
let resultNum = Number(newCardNum[i]);
sum += resultNum;
}
return sum;
}

//奇數位加總
function oddNum(newCardNum) {
let sum = 0;
for (let i = 0; i <= 15; i += 2) {
let resultNum = Number(newCardNum[i]) * 2;
if (resultNum >= 10) {
resultNum -= 9;
}
sum += resultNum;
}
return sum;
}

小結

  1. 先把需求架構寫出來,不要急著寫答案。
  2. 利用函式填空法專注於程式邏輯的編寫。
  3. 透過 console.log 把不確定的地方都印出來檢查是否與預期的相同。

參考資料