问题
Does NSRegularExpression
support named capture groups? It doesn't look like it from the documentation, but I wanted to check before I explore alternative solutions.
回答1:
Named grouping is not supported in iOS, all you can do as I see is to make use of Enum
:
Enum:
typedef enum
{
kDayGroup = 1,
kMonthGroup,
kYearGroup
} RegexDateGroupsSequence;
Sample Code:
NSString *string = @"07-12-2014";
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"(\\d{2})\\-(\\d{2})\\-(\\d{4}|\\d{2})"
options:NSRegularExpressionCaseInsensitive
error:&error];
NSArray *matches = [regex matchesInString:string
options:0
range:NSMakeRange(0, [string length])];
for (NSTextCheckingResult *match in matches) {
NSString *day = [string substringWithRange:[match rangeAtIndex:kDayGroup]];
NSString *month = [string substringWithRange:[match rangeAtIndex:kMonthGroup]];
NSString *year = [string substringWithRange:[match rangeAtIndex:kYearGroup]];
NSLog(@"Day: %@, Month: %@, Year: %@", day, month, year);
}
回答2:
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:@"^(?<city>.+), (?<state>[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).
回答3:
Since iOS 11 named capture groups are supported. See my answer here https://stackoverflow.com/a/47794474/1696733
来源:https://stackoverflow.com/questions/24814974/named-capture-groups-with-nsregularexpression