首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

VC-ATL 開發 COM 元件實戰系列(五):核心驗證邏輯實作與 Luhn 演算法

     編輯:VC 教學

本系列第五篇,進入 ValidateCard.cpp 實作核心驗證方法 ValidateCreditCard 及三大檢查演算法:Prefix(前綴)、Length(長度)、Luhn(模 10 校驗)。

一、ValidateCreditCard 總控流程

STDMETHODIMP CValidateCard::ValidateCreditCard(BSTR bstrCCNo, BSTR bstrCCType, long* val)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState()); // MFC 模組狀態切換

    CString strType(bstrCCType);
    strType.MakeUpper(); // 不區分大小寫

    // 卡別代碼映射
    if (strType == _T("VISA"))       bstrCCType = SysAllocString(OLESTR("V"));
    else if (strType == _T("MASTER")) bstrCCType = SysAllocString(OLESTR("M"));
    else if (strType == _T("AMERICAN")) bstrCCType = SysAllocString(OLESTR("A"));
    else {
        *val = 0; return S_FALSE; // 不支援卡別
    }

    // 三大檢查全部通過才有效
    if (PrefixCheck(bstrCCNo, bstrCCType) == S_OK &&
        LengthCheck(bstrCCNo, bstrCCType) == S_OK &&
        LuhnCheck(bstrCCNo, bstrCCType) == S_OK) {
        *val = 1; return S_OK;
    }
    *val = 0; return S_FALSE;
}

二、PrefixCheck:卡號前綴驗證

卡別代碼前綴規則範例
V (Visa)以 4 開頭4111 1111 1111 1111
M (MasterCard)51~55 或 2221~27205555 5555 5555 4444
A (American Express)34 或 373782 822463 10005
HRESULT CValidateCard::PrefixCheck(BSTR bstrCCNo, BSTR bstrCCType)
{
    CString strNo(bstrCCNo);
    strNo.Remove(_T(' ')); strNo.Remove(_T('-')); // 移除分隔符

    if (bstrCCType[0] == L'V') {
        return (strNo[0] == _T('4')) ? S_OK : S_FALSE;
    }
    else if (bstrCCType[0] == L'M') {
        int prefix2 = _ttoi(strNo.Left(2));
        int prefix4 = _ttoi(strNo.Left(4));
        return ((prefix2 >= 51 && prefix2 <= 55) || (prefix4 >= 2221 && prefix4 <= 2720)) ? S_OK : S_FALSE;
    }
    else if (bstrCCType[0] == L'A') {
        return (strNo.Left(2) == _T("34") || strNo.Left(2) == _T("37")) ? S_OK : S_FALSE;
    }
    return S_FALSE;
}

三、LengthCheck:卡號長度驗證

卡別長度
Visa13, 16, 19 碼
MasterCard16 碼
American Express15 碼
HRESULT CValidateCard::LengthCheck(BSTR bstrCCNo, BSTR bstrCCType)
{
    CString strNo(bstrCCNo);
    strNo.Remove(_T(' ')); strNo.Remove(_T('-'));
    int len = strNo.GetLength();

    if (bstrCCType[0] == L'V') return (len == 13 || len == 16 || len == 19) ? S_OK : S_FALSE;
    if (bstrCCType[0] == L'M') return (len == 16) ? S_OK : S_FALSE;
    if (bstrCCType[0] == L'A') return (len == 15) ? S_OK : S_FALSE;
    return S_FALSE;
}

四、LuhnCheck:模 10 校驗演算法(核心)

Luhn 演算法步驟:

  1. 從右往左(不含檢查碼),每第二位數字乘 2。
  2. 若乘積 ≥ 10,減 9(或將十位個位相加)。
  3. 所有數字相加,總和模 10 為 0 則合法。
HRESULT CValidateCard::LuhnCheck(BSTR bstrCCNo, BSTR bstrCCType)
{
    CString strNo(bstrCCNo);
    strNo.Remove(_T(' ')); strNo.Remove(_T('-'));

    int sum = 0;
    bool doubleDigit = false;
    for (int i = strNo.GetLength() - 1; i >= 0; --i) {
        int digit = strNo[i] - _T('0');
        if (digit < 0 || digit > 9) return S_FALSE; // 非數字

        if (doubleDigit) {
            digit *= 2;
            if (digit > 9) digit -= 9;
        }
        sum += digit;
        doubleDigit = !doubleDigit;
    }
    return (sum % 10 == 0) ? S_OK : S_FALSE;
}

五、單元測試資料集

卡別卡號預期結果說明
VISA4111 1111 1111 1111Valid標準測試卡
MASTER5555 5555 5555 4444Valid標準測試卡
AMEX3782 822463 10005Valid標準測試卡
VISA4111 1111 1111 1112Invalid檢查碼錯誤
MASTER5105 1051 0510 5100ValidMasterCard 2-series BIN

六、擴充建議

  • 支援更多卡別:Discover (6011, 65)、JCB (3528~3589)、UnionPay (62) 等。
  • 輸入正規化:統一移除空格、連字號、全形數字轉半形。
  • 效能優化:Luhn 可用查表法(預計算 0~9 乘 2 後值)避免分支。
  • 錯誤碼細分:回傳 enum 或結構體區分「前綴錯」、「長度錯」、「校驗錯」,方便前端提示。

核心驗證邏輯完成,下一篇將示範如何建立安裝專案、註冊 COM 元件、處理版本升級與相容性。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved