捕获组不适用于 NSRegularExpression

Capturing group does not work with NSRegularExpression

我正在尝试 NSRegularExpression 使用捕获组模式。我有字符串 abc{=2} 和正则表达式模式 {(.+)} 来获取 =2 字符串,但每次创建 NSRegularExpression 实例的尝试都以

结尾
Optional(Error Domain=NSCocoaErrorDomain Code=2048 "The operation couldn’t be completed. (Cocoa error 2048.)" UserInfo=0x7fad7253cb40 {NSInvalidValue={(.+)}})

代码:

var error: NSError?
let regexp = NSRegularExpression(pattern: "{(.+)}", options: .CaseInsensitive, error: &error)
println("error = \(error)")

我找不到这个模式有什么问题。我正在使用 regex101.com 页面并且它在那里工作。

提前致谢!

编辑

我看到转义大括号 (\{(.+)\}) 解决了错误问题,但后来我得到了 {=2} 而不是 =2.

我用不同的模式解决了这个问题。我现在不知道 regex101.com 是否匹配错误,我的模式的正确匹配是 {=2} 而不是 '=2'。

我使用积极的后视和积极的前瞻来匹配这个。这是模式:

(?<=\{)(.+)(?=\})

这是 NSRegularExpression 的一个特点,也许 NSTextCheckingResult 更是如此。您捕获的范围实际上是 NSTextCheckingResult 结果实例的索引 1 处的范围。

一个例子:

let rx = NSRegularExpression(pattern: "\{(.+?)\}", options: .CaseInsensitive, error: nil)!
let str = "abc{=2}"
let strRange = NSMakeRange(0, count(str))

rx.enumerateMatchesInString(str, options: nil, range: strRange, usingBlock: { result, flags, stop in
    if let range0 = result?.range {
        println( (str as NSString).substringWithRange(range0) ) // "{=2}"
    }
    if let range1 = result?.rangeAtIndex(1) {
        println( (str as NSString).substringWithRange(range1) ) // "=2" <-- this is what you want!
    }
})

对于每个 NSTextCheckingResult 实例,索引 0 处的范围是表示捕获整个模式的范围(range 属性 是索引的快捷方式0).您的捕获组范围位于索引 1 及以后。 From the NSTextCheckingResult docs rangeAtIndex: method:

A result must have at least one range, but may optionally have more (for example, to represent regular expression capture groups).

理解这一点的最简单方法是想象您提供了一个没有捕获组的正则表达式模式。 NSTextCheckingResult 实例会匹配和表示什么?整个匹配模式!

最好使用 NSTextCheckingResult's numberOfRanges property 来确保在尝试访问捕获组的范围之前捕获了 1 个以上的范围。如果您使用的是一个捕获组,那么当您的捕获组找到匹配项时,您应该期望 numberOfRanges 为 2。

最后,虽然这不是必需的,但我将 ? 修饰符添加到您的捕获组 (.+) 中以生成 (.+?)。您的模式最初在捕获组内是贪婪的,而 ? 使模式不贪婪。我发现在使用正则表达式时,非贪婪通常更容易预测。


我还应该提及您的解决方案有效的原因(结果在索引 0 处)。通过使用 lookahead/lookbehind,您已经有效地从您的模式中完全排除了 {} 大括号。如果你检查你的结果,你应该看到你的捕获组结果实际上存在于索引 1(但给出与索引 0 相同的结果)。