NSRegularExpression
是否支持命名捕获组?它看起来不像the documentation,但我想在探索替代解决方案之前检查一下。
答案 0 :(得分:10)
iOS不支持命名分组,我所能做的就是使用Enum
:
typedef enum
{
kDayGroup = 1,
kMonthGroup,
kYearGroup
} RegexDateGroupsSequence;
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);
}
答案 1 :(得分:4)
iOS 11使用-[NSTextCheckingResult rangeWithName:]
API引入了命名捕获支持。
要获取带有相关值的命名捕获字典,您可以使用此扩展(用Swift编写,但可以从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
}
}
来自Objective-C的电话:
(lldb) po [@"San Francisco, CA" dictionaryByMatchingRegex:@"^(?<city>.+), (?<state>[A-Z]{2})$"];
{
city = "San Francisco";
state = CA;
}
代码说明:该函数首先需要找出命名捕获的列表。不幸的是,Apple没有为此发布API(rdar://36612942)。
答案 2 :(得分:1)
由于支持iOS 11命名的捕获组。请在此处查看我的回答https://stackoverflow.com/a/47794474/1696733
答案 3 :(得分:0)
从iOS 11开始,我可以使用NSTextCheckingResult
的扩展名来获取命名组的值:
extension NSTextCheckingResult {
func match(withName name: String, in string: String) -> String? {
let matchRange = range(withName: name)
guard matchRange.length > 0 else {
return nil
}
let start = string.index(string.startIndex, offsetBy: matchRange.location)
return String(string[start..<string.index(start, offsetBy: matchRange.length)])
}
}
用法:
let re = try! NSRegularExpression(pattern: "(?:(?<hours>\\d+):)(?:(?<minutes>\\d+):)?(?<seconds>\\d+)", options: [])
var str = "40 16:00:00.200000"
let result = re.firstMatch(in: str, options: [], range: NSRange(location: 0, length: str.count))
result?.match(withName: "hours", in: str) // 16