原文
不小心在推特上浏览到一个文章,很好的诠释了什么是swifty的swift代码。
如何检测一个信用卡类型呢,参数如下表格所示(主要的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
这里有段现成的代码 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") { ... }
// ...
这特么是什么鬼代码,别人维护起来得多痛苦,尤其是银行玩点幺蛾子多改下的时候,修改这些代码简直是噩梦
Option 2:正则大法
现在我们用正则来替代if大法
//amex starts with 34 or 37 and is 15 digits
case .amex:
return "^3[47][0-9]{13}$"
很cooool 很简洁是吧,现在来看看.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}$"
...
黑人问号???
正则表达式是个很强大的工具,但是正则在表达式在表达数值范围时候就显得不那么优雅了,更别说是这种可变长度的数字,而且还很不好懂,这也pass。
一个更简洁,具有变现力点代码:
我们用的是swift,肯定有一种更好的方式来处理类似的情况,先别换编译器的嘲笑,我们先写点伪代码,
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]
现在判断的规则是不是变的相当的简洁明了,如何做到呢,你可以先看代码 CardParser.swift.
强大的ENUM:
CardType是swift的中枚举类型,swift枚举是个强大的武器不但可以进行模式匹配还可以验证规则:
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
强大的协议
待续