Skip to content

Instantly share code, notes, and snippets.

@d-date
Created October 11, 2024 09:09

Revisions

  1. d-date created this gist Oct 11, 2024.
    67 changes: 67 additions & 0 deletions CreditCardBrand.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,67 @@
    enum CreditCardBrand: String {
    enum Pattern {
    static let visa = #"^4[0-9]{12}(?:[0-9]{3})?"#
    static let master = #"^(?: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}$"#
    static let amex = #"^3[47][0-9]{13}$"#
    static let diners = #"^3(?:0[0-5]|[68][0-9])[0-9]{11,13}$"#
    static let discover = #"^6(?:011|5[0-9]{2})[0-9]{12}$"#
    static let jcb = #"^(?:2131|1800|35\d{3})\d{7}"#
    }

    case visa = "Visa"
    case master = "Master"
    case amex = "Amex"
    case diners = "Diners"
    case discover = "Discover"
    case jcb = "JCB"

    init?(cardBrand: CafeAPIClient.CreditCard.CardBrand) {
    switch cardBrand {
    case .americanExpress:
    self = .amex

    case .dinersClub:
    self = .diners

    case .discover:
    self = .discover

    case .jcb:
    self = .jcb

    case .masterCard:
    self = .master

    case .visa:
    self = .visa

    case .unknown:
    return nil
    }
    }

    init?(cardNumber: String) {
    switch cardNumber {
    case Regex(pattern: Pattern.visa):
    self = .visa

    case Regex(pattern: Pattern.master):
    self = .master

    case Regex(pattern: Pattern.amex):
    self = .amex

    case Regex(pattern: Pattern.diners):
    self = .diners

    case Regex(pattern: Pattern.discover):
    self = .discover

    case Regex(pattern: Pattern.jcb):
    self = .jcb

    default:
    return nil
    }
    }
    }
    38 changes: 38 additions & 0 deletions Regex.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,38 @@
    import Foundation

    protocol RegularExpressionMatchable {
    func match(regex: Regex) -> Bool
    }

    extension String: RegularExpressionMatchable {
    func match(regex: Regex) -> Bool {
    regex.match(string: self)
    }
    }

    func ~= <T: RegularExpressionMatchable>(pattern: Regex, matchable: T) -> Bool {
    matchable.match(regex: pattern)
    }

    struct Regex {
    let pattern: String
    let options: NSRegularExpression.Options

    init(pattern: String, options: NSRegularExpression.Options = []) {
    self.pattern = pattern
    self.options = options
    }

    private var matcher: NSRegularExpression {
    do {
    return try NSRegularExpression(pattern: pattern, options: options)
    } catch {
    print(error)
    fatalError()
    }
    }

    func match(string: String, options: NSRegularExpression.MatchingOptions = []) -> Bool {
    matcher.firstMatch(in: string, options: options, range: .init(location: 0, length: string.count)) != nil
    }
    }