IOS 11 introduced support for a capture name using the API -[NSTextCheckingResult rangeWithName:] .
To get a dictionary of named captures with associated values, you can use this extension (written in Swift, but called from Objective-C):
@objc extension NSString { public func dictionaryByMatching(regex regexString: String) -> [String: String]? { let string = self as String guard let nameRegex = try? NSRegularExpression(pattern: "\\(\\?\\<(\\w+)\\>", options: []) else {return nil} let nameMatches = nameRegex.matches(in: regexString, options: [], range: NSMakeRange(0, regexString.count)) let names = nameMatches.map { (textCheckingResult) -> String in return (regexString as NSString).substring(with: textCheckingResult.range(at: 1)) } guard let regex = try? NSRegularExpression(pattern: regexString, options: []) else {return nil} let result = regex.firstMatch(in: string, options: [], range: NSMakeRange(0, string.count)) var dict = [String: String]() for name in names { if let range = result?.range(withName: name), range.location != NSNotFound { dict[name] = self.substring(with: range) } } return dict.count > 0 ? dict : nil } }
A call from Objective-C:
(lldb) po [@"San Francisco, CA" dictionaryByMatchingRegex:@"^(?<city>.+), (?<state>[AZ]{2})$"]; { city = "San Francisco"; state = CA; }
Code designation. First, the function should find a list of named captures. Unfortunately, Apple has not published an API for this ( rdar: // 36612942 ).
Ortwin gentz
source share