Does NSRegularExpression
support named capture groups? It doesn\'t look like it from the documentation, but I wanted to check before I explore alternative solut
iOS 11 introduced named capture support using the -[NSTextCheckingResult rangeWithName:]
API.
To get a dictionary of named captures with their associated values you can use this extension (written in Swift, but can be 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
}
}
Call from Objective-C:
(lldb) po [@"San Francisco, CA" dictionaryByMatchingRegex:@"^(?.+), (?[A-Z]{2})$"];
{
city = "San Francisco";
state = CA;
}
Code explanation: The function first needs to find out the list of named captures. Unfortunately, Apple didn't publish an API for that (rdar://36612942).