Swift: Как проверить номер социального страхования (SSN)?
Как я могу подтвердить, что String
кодирует действительный американский номер социального страхования (SSN), например 123-45-6789
, используя Swift?
Validate означает, чтобы проверить, соответствует ли данная строка шаблону 123-45-6789
,
2 ответа
Просто:
Шаг 1. создать метод:
func isValidSsn(_ ssn: String) -> Bool {
let ssnRegext = "^(?!(000|666|9))\\d{3}-(?!00)\\d{2}-(?!0000)\\d{4}$"
return ssn.range(of: ssnRegext, options: .regularExpression, range: nil, locale: nil) != nil
}
Шаг 2. Используй это:
let ssn = "123-45-6789"
validateSsn(ssn) // true
Надеюсь, поможет!
Для этого лучше всего использовать пользовательский тип. У него есть неисправный инициализатор, который вы используете для инициализации его из строки. Если у вас есть экземпляр SSN, отличный от nil, вы знаете, что это действительный SSN, и вам больше не нужно проверять его.
Я разбираю SSN в UInt32
и при необходимости сериализовать его обратно в строку. Это предотвращает издержки ARC и памяти кучи, связанные с выделением и передачей строк. Вот реализация:
import Foundation
struct SSN {
// Stores aaa-bb-ccc as aaabbbccc
let ssn: UInt32
init?(_ string: String) {
let segments = string.split(separator: "-")
guard segments.lazy.map({ $0.count }) == [3, 2, 3] else {
debugPrint("SSN segments must be lenght 3, 2, 3 (e.g. 123-45-678).")
return nil
}
guard !zip(segments, ["000", "00", "000"]).contains(where: {$0.0 == $0.1}) else {
debugPrint("SSN segments cannot be all zeros.")
return nil
}
let firstSegment = segments[0]
guard firstSegment != "666", !firstSegment.hasPrefix("9") else {
debugPrint("The first SSN segment (\(firstSegment)) cannot be 666, or be in the range 900-999.")
return nil
}
let dashesRemoved = string.replacingOccurrences(of: "-", with: "")
self.ssn = UInt32(dashesRemoved)!
}
}
extension SSN: ExpressibleByStringLiteral {
init(stringLiteral literalString: String) {
self.init(literalString)!
}
}
extension SSN: CustomStringConvertible {
var description: String {
let formatter = NumberFormatter()
formatter.minimumIntegerDigits = 3
let segment1 = formatter.string(from: NSNumber(value: self.ssn / 100000))!
formatter.minimumIntegerDigits = 2
let segment2 = formatter.string(from: NSNumber(value: (self.ssn / 1000) % 100))!
formatter.minimumIntegerDigits = 3
let segment3 = formatter.string(from: NSNumber(value: self.ssn % 1000))!
return "\(segment1)-\(segment2)-\(segment3)"
}
}
И некоторые тесты:
let testSSNString = "123-45-678"
let optionalTestSSN = SSN(testSSNString)
guard let testSSN = optionalTestSSN else {
assertionFailure("Valid SSN (\(testSSNString)) wasn't successfully parsed.")
fatalError()
}
assert(testSSN.description == testSSNString, "SSN (\(testSSN)) was not correctly converted back to String.")
func assertSSNShouldBeNil(_ string: String, because reason: String) {
assert(SSN(string) == nil, reason + " should be nil.")
}
assertSSNShouldBeNil("123-45-678-9", because: "SSN with too many segment")
assertSSNShouldBeNil("123-45", because: "SSN with too few segments")
assertSSNShouldBeNil("", because: "Empty SSN")
assertSSNShouldBeNil("000-12-345", because: "SSN with all-zero segment 1")
assertSSNShouldBeNil("123-00-456", because: "SSN with all-zero segment 2")
assertSSNShouldBeNil("123-45-000", because: "SSN with all-zero segment 3")
assertSSNShouldBeNil("666-12-345", because: "SSN starting with 666")
assertSSNShouldBeNil("900-12-345", because: "SSN starting with number in range 900-999")
assertSSNShouldBeNil("999-12-345", because: "SSN starting with number in range 900-999")