NSRegularExpression in Swift
Extending String to do simple pattern matching
Section titled “Extending String to do simple pattern matching”extension String { func matchesPattern(pattern: String) -> Bool { do { let regex = try NSRegularExpression(pattern: pattern, options: NSRegularExpressionOptions(rawValue: 0)) let range: NSRange = NSMakeRange(0, self.characters.count) let matches = regex.matchesInString(self, options: NSMatchingOptions(), range: range) return matches.count > 0 } catch _ { return false } }}
// very basic examples - check for specific stringsdump("Pinkman".matchesPattern("(White|Pinkman|Goodman|Schrader|Fring)"))
// using character groups to check for similar-sounding impressionist paintersdump("Monet".matchesPattern("(M[oa]net)"))dump("Manet".matchesPattern("(M[oa]net)"))dump("Money".matchesPattern("(M[oa]net)")) // false
// check surname is in listdump("Skyler White".matchesPattern("\\w+ (White|Pinkman|Goodman|Schrader|Fring)"))
// check if string looks like a UK stock tickerdump("VOD.L".matchesPattern("[A-Z]{2,3}\\.L"))dump("BP.L".matchesPattern("[A-Z]{2,3}\\.L"))
// check entire string is printable ASCII charactersdump("tab\tformatted text".matchesPattern("^[\u{0020}-\u{007e}]*$"))
// Unicode example: check if string contains a playing card suitdump("♠︎".matchesPattern("[\u{2660}-\u{2667}]"))dump("♡".matchesPattern("[\u{2660}-\u{2667}]"))dump("😂".matchesPattern("[\u{2660}-\u{2667}]")) // false
// NOTE: regex needs Unicode-escaped charactersdump("♣︎".matchesPattern("♣︎")) // does NOT workBelow is another example which builds on the above to do something useful, which can’t easily be done by any other method and lends itself well to a regex solution.
// Pattern validation for a UK postcode.// This simply checks that the format looks like a valid UK postcode and should not fail on false positives.private func isPostcodeValid(postcode: String) -> Bool { return postcode.matchesPattern("^[A-Z]{1,2}([0-9][A-Z]|[0-9]{1,2})\\s[0-9][A-Z]{2}")}
// valid patterns (from https://en.wikipedia.org/wiki/Postcodes_in_the_United_Kingdom#Validation)// will return truedump(isPostcodeValid("EC1A 1BB"))dump(isPostcodeValid("W1A 0AX"))dump(isPostcodeValid("M1 1AE"))dump(isPostcodeValid("B33 8TH"))dump(isPostcodeValid("CR2 6XH"))dump(isPostcodeValid("DN55 1PT"))
// some invalid patterns// will return falsedump(isPostcodeValid("EC12A 1BB"))dump(isPostcodeValid("CRB1 6XH"))dump(isPostcodeValid("CR 6XH"))Basic Usage
Section titled “Basic Usage”There are several considerations when implementing Regular Expressions in Swift.
let letters = "abcdefg"let pattern = "[a,b,c]"let regEx = try NSRegularExpression(pattern: pattern, options: [])let nsString = letters as NSStringlet matches = regEx.matches(in: letters, options: [], range: NSMakeRange(0, nsString.length))let output = matches.map {nsString.substring(with: $0.range)}//output = ["a", "b", "c"]In order to get an accurate range length that supports all character types the input string must be converted to a NSString.
For safety matching against a pattern should be enclosed in a do catch block to handle failure
let numbers = "121314"let pattern = "1[2,3]"do { let regEx = try NSRegularExpression(pattern: pattern, options: []) let nsString = numbers as NSString let matches = regEx.matches(in: numbers, options: [], range: NSMakeRange(0, nsString.length)) let output = matches.map {nsString.substring(with: $0.range)} output} catch let error as NSError { print("Matching failed")}//output = ["12", "13"]Regular expression functionality is often put in an extension or helper to seperate concerns.
Replacing Substrings
Section titled “Replacing Substrings”Patterns can be used to replace part of an input string.
The example below replaces the cent symbol with the dollar symbol.
var money = "¢¥€£$¥€£¢"let pattern = "¢"do { let regEx = try NSRegularExpression (pattern: pattern, options: []) let nsString = money as NSString let range = NSMakeRange(0, nsString.length) let correct$ = regEx.stringByReplacingMatches(in: money, options: .withTransparentBounds, range: range, withTemplate: "$")} catch let error as NSError { print("Matching failed")}//correct$ = "$¥€£$¥€£$"Special Characters
Section titled “Special Characters”To match special characters Double Backslash should be used
\. becomes \\.
Characters you’ll have to escape include
(){}[]/\+*$>.|^?The below example get three kinds of opening brackets
let specials = "(){}[]"let pattern = "(\\(|\\{|\\[)"do { let regEx = try NSRegularExpression(pattern: pattern, options: []) let nsString = specials as NSString let matches = regEx.matches(in: specials, options: [], range: NSMakeRange(0, nsString.length)) let output = matches.map {nsString.substring(with: $0.range)}} catch let error as NSError { print("Matching failed")}//output = ["(", "{", "["]Validation
Section titled “Validation”Regular expressions can be used to validate inputs by counting the number of matches.
var validDate = false
let numbers = "35/12/2016"let usPattern = "^(0[1-9]|1[012])[-/.](0[1-9]|[12][0-9]|3[01])[-/.](19|20)\\d\\d$"let ukPattern = "^(0[1-9]|[12][0-9]|3[01])[-/](0[1-9]|1[012])[-/](19|20)\\d\\d$"do { let regEx = try NSRegularExpression(pattern: ukPattern, options: []) let nsString = numbers as NSString let matches = regEx.matches(in: numbers, options: [], range: NSMakeRange(0, nsString.length))
if matches.count > 0 { validDate = true }
validDate
} catch let error as NSError { print("Matching failed")}//output = falseNSRegularExpression for mail validation
Section titled “NSRegularExpression for mail validation”func isValidEmail(email: String) -> Bool {
let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}"
let emailTest = NSPredicate(format:"SELF MATCHES %@", emailRegEx) return emailTest.evaluate(with: email)}or you could use String extension like this:
extension String{ func isValidEmail() -> Bool {
let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}"
let emailTest = NSPredicate(format:"SELF MATCHES %@", emailRegEx) return emailTest.evaluate(with: self) }}Remarks
Section titled “Remarks”Special Characters
*?+[(){}^$|\./