import Foundation
let pattern = #"(?i)(?=(\d)\d)(?<![\d\-\x{2013}\x{2014}%])(?!000|666|9\d\d|\d{3}00|\d{5}0000|\1{9}|012345678|123456789|234567890|098765432|876543210|078051120|219099999)\d{9}(?![\d\-\x{2013}\x{2014}%])(?!\.(?:pdf|docx?|xlsx?|pptx?|zip|jpe?g|png|txt|log)\b)"#
let regex = try! NSRegularExpression(pattern: pattern, options: .anchorsMatchLines)
let testString = #################"""
################
## Must match:
################
009958881
123454891 is my ssn
my ssn is 123454891
my ssn is 123454891 ok?
my ssn is 123454891.
my ssn is:123454891.
# This one sneaks though, but we can live with that, maybe?
myssnnumberis123454891ok?
################
## Must not match:
################
# All-Zero group sequences
231840000
231007289
000877289
# Starting with 9
908780485
# Starting with 666
666780485
# Same number sequences:
222222222
555555555
# Ascending/Descending sequences:
123456789
87654321
# Known invalidated SSN:
219099999
078051120
# File names with common extensions:
123454891.pdf
123454891.xlsx
Check the attachment: 123454891.xls, then get back to me.
Check the attachment: 123454891.jpeg, then get back to me.
# Extra digits:
1123454891
1234548911
# Unsupported boundaries:
–123454891
—123454891
%123454891
123454891-
123454891—
123454891%
1-123454891
123454891-1
# Valid SSN with separators:
123-45-4891
098-18-6564
123-45-4848
702-02-0202
001-14-0004
009 95 8881
123-45-4891 is my ssn
my ssn is 123-45-4891
my ssn is 123-45-4891 ok?
my ssn is 123-45-4891.
123 45 4891 is my ssn
my ssn is 123 45 4891
my ssn is 123 45 4891 ok?
my ssn is 123 45 4891.
my ssn is:123-45-4891.
my ssn is:123 45 4891.
ss#123-45-4891
ssn123-45-4891
# Emdash separator:
123–45–4891
# Endash separator:
123—45—4891
# Slash separator
123/45/4891
# Telephone
1-234-567-8901
1-234-567-8901
1-234-567-8901
1 (234) 567-8901
12347658901
# Credit card
5500 0000 0000 0004
3400 0000 0000 009
3000 0000 0000 04
5500-1244-2232-0004
3400-1244-0000-009
3000-1244-1234-04
# Random Numbers
1234567890112371298739872891738912738937289d712897381297381927d3128937893d7218947d1892742189duc89789v127c897412987893c12893c79
122-426-389
187-5-43212
187-0-43212
2423-45-6789
# Unsupported boundaries:
ssn-123-45-4891
123-45-4891-ssn
"""#################
let stringRange = NSRange(location: 0, length: testString.utf16.count)
let matches = regex.matches(in: testString, range: stringRange)
var result: [[String]] = []
for match in matches {
var groups: [String] = []
for rangeIndex in 1 ..< match.numberOfRanges {
let nsRange = match.range(at: rangeIndex)
guard !NSEqualRanges(nsRange, NSMakeRange(NSNotFound, 0)) else { continue }
let string = (testString as NSString).substring(with: nsRange)
groups.append(string)
}
if !groups.isEmpty {
result.append(groups)
}
}
print(result)
Please keep in mind that these code samples are automatically generated and are not guaranteed to work. If you find any syntax errors, feel free to submit a bug report. For a full regex reference for Swift 5.2, please visit: https://developer.apple.com/documentation/foundation/nsregularexpression