Skip to content

Instantly share code, notes, and snippets.

@rsaenzi
Created July 12, 2019 22:37
Show Gist options
  • Select an option

  • Save rsaenzi/d9e655c0c953f90a3a485882c628b59e to your computer and use it in GitHub Desktop.

Select an option

Save rsaenzi/d9e655c0c953f90a3a485882c628b59e to your computer and use it in GitHub Desktop.
Enum to handle credit card issuers for iOS
//
// CreditCardType.swift
//
// Created by Rigoberto Sáenz Imbacuán (https://www.linkedin.com/in/rsaenzi/)
// Copyright © 2019. All rights reserved.
//
enum CreditCardType: String, Codable {
case visa = "VISA"
case visaElectron = "VISA_ELECTRON"
case mastercard = "MASTERCARD"
case maestro = "MAESTRO"
case americanExpress = "AMERICAN_EXPRESS"
case dinersClub = "DINERS_CLUB"
case discover = "DISCOVER"
case jcb = "JCB"
}
extension CreditCardType {
static var all: [CreditCardType] {
return [
.visa,
.visaElectron,
.mastercard,
.maestro,
.americanExpress,
.dinersClub,
.discover,
.jcb
]
}
static func getCreditCardType(fromTypeName rawTypeName: String?) -> CreditCardType? {
guard let typeNameToTest = rawTypeName else {
return nil
}
if typeNameToTest.lowercased() == CreditCardType.visa.rawValue.lowercased() {
return .visa
} else if typeNameToTest.lowercased() == CreditCardType.visaElectron.rawValue.lowercased() {
return .visaElectron
} else if typeNameToTest.lowercased() == CreditCardType.mastercard.rawValue.lowercased() {
return .mastercard
} else if typeNameToTest.lowercased() == CreditCardType.maestro.rawValue.lowercased() {
return .maestro
} else if typeNameToTest.lowercased() == CreditCardType.americanExpress.rawValue.lowercased() {
return .americanExpress
} else if typeNameToTest.lowercased() == CreditCardType.dinersClub.rawValue.lowercased() {
return .dinersClub
} else if typeNameToTest.lowercased() == CreditCardType.discover.rawValue.lowercased() {
return .discover
} else if typeNameToTest.lowercased() == CreditCardType.jcb.rawValue.lowercased() {
return .jcb
}
return nil
}
static func getCreditCardType(fromNumber rawCardNumber: String?) -> CreditCardType? {
guard let rawValidCardNumber = rawCardNumber else {
return nil
}
// Removes all non-digits
let numberToTest = rawValidCardNumber.removeCharacters(from: CharacterSet.decimalDigits.inverted)
if CreditCardType.visa.doesCardNumberBelongsToCreditCardType(numberToTest) {
return .visa
} else if CreditCardType.visaElectron.doesCardNumberBelongsToCreditCardType(numberToTest) {
return .visaElectron
} else if CreditCardType.mastercard.doesCardNumberBelongsToCreditCardType(numberToTest) {
return .mastercard
} else if CreditCardType.maestro.doesCardNumberBelongsToCreditCardType(numberToTest) {
return .maestro
} else if CreditCardType.americanExpress.doesCardNumberBelongsToCreditCardType(numberToTest) {
return .americanExpress
} else if CreditCardType.dinersClub.doesCardNumberBelongsToCreditCardType(numberToTest) {
return .dinersClub
} else if CreditCardType.discover.doesCardNumberBelongsToCreditCardType(numberToTest) {
return .discover
} else if CreditCardType.jcb.doesCardNumberBelongsToCreditCardType(numberToTest) {
return .jcb
}
return nil
}
}
extension CreditCardType {
var icon: UIImage {
switch self {
case .visa: return #imageLiteral(resourceName: "CardVisa")
case .visaElectron: return #imageLiteral(resourceName: "CardVisaElectron")
case .mastercard: return #imageLiteral(resourceName: "CardMastercard")
case .maestro: return #imageLiteral(resourceName: "CardMaestro")
case .americanExpress: return #imageLiteral(resourceName: "CardAmericanExpress")
case .dinersClub: return #imageLiteral(resourceName: "CardDinersClub")
case .discover: return #imageLiteral(resourceName: "CardDiscover")
case .jcb: return #imageLiteral(resourceName: "CardJCB")
}
}
var regexPattern: String {
switch self {
case .visa: return "^4[0-9]{12}(?:[0-9]{3})?$"
case .visaElectron: return "^(4026|417500|4508|4844|491(3|7))"
case .mastercard: return "^5[1-5][0-9]{14}$"
case .maestro: return "^(5018|5020|5038|6304|6759|676[1-3])"
case .americanExpress: return "^3[47][0-9]{13}$"
case .dinersClub: return "^3(?:0[0-5]|[68][0-9])[0-9]{11}$"
case .discover: return "^6(?:011|5[0-9]{2})[0-9]{12}$"
case .jcb: return "^(?:2131|1800|35\\d{3})\\d{11}$"
}
}
var exampleValue: String {
switch self {
case .visa: return "4111111111111111"
case .visaElectron: return "4026000000000002"
case .mastercard: return "5538383883833838"
case .maestro: return "501800000009"
case .americanExpress: return "347000000000000"
case .dinersClub: return "30099999999999"
case .discover: return "6550000000000000"
case .jcb: return "180000000000000"
}
}
private func doesCardNumberBelongsToCreditCardType(_ cardNumber: String) -> Bool {
do {
let regex = try NSRegularExpression(pattern: regexPattern,
options: .caseInsensitive)
return regex.matches(in: cardNumber,
options: [],
range: NSMakeRange(0, cardNumber.count)).count > 0
} catch {
return false
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment