重構(gòu)出更加swifty的代碼

原文
不小心在推特上瀏覽到一個文章,很好的詮釋了什么是swifty的swift代碼。
如何檢測一個信用卡類型呢,參數(shù)如下表格所示(主要的4個,還有各種亂七八糟的)

Issuing Network IIN ranges Card Number Length
American Express 34, 37 15
MasterCard 51–55,2221–2720 16
Visa 4 13, 16, 19
Discover 65,6011,644–649,622126–622925 16, 19

Option 1: if大法

先來試試最粗暴的算法:

如果是4開頭就是visa,如果是3開頭則可能是Amex, Diners, or JCB,如果是6開頭則可能是Discover

這里有段現(xiàn)成的代碼 PaymentKit,翻譯成swift大概就是這樣

// ...
// Discover
if cardString.hasPrefix("6011") || cardString.hasPrefix("65") {
    return .discover
}
else if cardString.hasPrefix("622") {
    // If the number has a prefix in the range 622126-622925, it's Discover
    let prefixLength = 6;
    if (cardString.characters.count >= prefixLength) {
        let prefixIndex = number.index(cardString.startIndex, offsetBy: prefixLength)
        let sixDigitPrefixString = cardString.substring(to: prefixIndex)
        let sixDigitPrefixInt = Int(sixDigitPrefixString)!
        if sixDigitPrefixInt >= 622126 && sixDigitPrefixInt <= 622925 {
            return .discover;
        }
    }
    return .unknown
}
else if cardString.hasPrefix("64") { ... }
// ...

這特么是什么鬼代碼,別人維護(hù)起來得多痛苦,尤其是銀行玩點(diǎn)幺蛾子多改下的時候,修改這些代碼簡直是噩夢

Option 2:正則大法

現(xiàn)在我們用正則來替代if大法

//amex starts with 34 or 37 and is 15 digits
case .amex:
    return "^3[47][0-9]{13}$"

很cooool 很簡潔是吧,現(xiàn)在來看看.masterCard:

//MasterCard starts with 51 through 55 
//or 2221 through 2720. All have 16 digits.
case .masterCard:
   return "^(?:5[1-5][0-9]{2}|" +
            "222[1-9]|" +
            "22[3-9][0-9]|" +
            "2[3-6][0-9]{2}|" +
            "27[01][0-9]|" +
            "2720)" +
            "[0-9]{12}$"
...

黑人問號???
正則表達(dá)式是個很強(qiáng)大的工具,但是正則在表達(dá)式在表達(dá)數(shù)值范圍時候就顯得不那么優(yōu)雅了,更別說是這種可變長度的數(shù)字,而且還很不好懂,這也pass。

一個更簡潔,具有變現(xiàn)力點(diǎn)代碼:

我們用的是swift,肯定有一種更好的方式來處理類似的情況,先別換編譯器的嘲笑,我們先寫點(diǎn)偽代碼,

case .amex:         prefix = ["34", "37"]
                    length = [15]
 
case .diners:       prefix = ["300"..."305", "309", "36", "38"..."39"]
                    length = [14]
 
case .discover:     prefix = ["6011", "65", "644"..."649", "622126"..."622925"]
                    length = [16]
 
case .jcb:          prefix = ["3528"..."3589"]
                    length = [16]
 
case .masterCard:   prefix = ["51"..."55", "2221"..."2720"]
                    length = [16]
 
case .visa:         prefix = ["4"]
                    length = [13, 16, 19]

現(xiàn)在判斷的規(guī)則是不是變的相當(dāng)?shù)暮啙嵜髁?,如何做到呢,你可以先看代碼 CardParser.swift.

強(qiáng)大的ENUM:

CardType是swift的中枚舉類型,swift枚舉是個強(qiáng)大的武器不但可以進(jìn)行模式匹配還可以驗(yàn)證規(guī)則:

enum CardType {
    case visa
    case masterCard
    ...
 
    var segmentGroupings: [Int] {...}
    var cvvLength: Int {...}
    ...
 
    func isValid(_ accountNumber: String) -> Bool {...}
    func isPrefixValid(_ accountNumber: String) -> Bool {...}
}

visa.cvvLength          // 3
visa.isPrefixValid("4") // true
visa.isValid("4")       // false

強(qiáng)大的協(xié)議

待續(xù)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容