NSRegularExpression.replacementString 不跟踪字符串长度的变化

NSRegularExpression.replacementString doesn't track changes in string length

我正在尝试编写一些代码,在其中迭代字符串中的正则表达式匹配项和 运行 对匹配项的操作,并将其替换为操作结果。不过,我 运行 遇到了问题,如果之前的替换字符串不准确,我的 replacementString() 覆盖提供的第二个和后续匹配项的范围与源字符串中的位置不匹配与原始匹配子字符串的长度相同。

我构建了一个简单的例子来演示这个问题。

var str : NSMutableString = "Hello, hello, jello!"

class MyConverter : NSRegularExpression {
    override func replacementString(for result: NSTextCheckingResult,
                                    in string: String,
                                    offset: Int,
                                    template templ: String) -> String {

        let theRange = result.range(at: 0)
        let theSubStr = NSString(string: string).substring(with: theRange)
        return super.replacementString(for: result,
                                       in: string,
                                       offset: offset,
                                       template: self.magic(theSubStr))
    }

    func magic(_ text: String) -> String {
        print("Converting \(text) to lloy")
        return "lloy"
    }
}

var regex = try? MyConverter(pattern: "llo", options: [])
let matches = regex?.replaceMatches(in: str,
                                    options: [],
                                    range: NSRange(location: 0, length: str.length),
                                    withTemplate: "[=11=]")
print(str)

我期望的输出是:

Converting llo to lloy
Converting llo to lloy
Converting llo to lloy
Helloy, helloy, jelloy!

但是,我得到的输出是这样的:

Converting llo to lloy
Converting ell to lloy
Converting jel to lloy
Helloy, helloy, jelloy!

最后的替换被放在正确的位置,但由于我试图 运行 对匹配文本的操作,我需要正确的子字符串出现在我的 magic() 方法中.

我可以尝试跟踪匹配项和生成的替换字符串之间的差异,并通过 +/- 修改每个范围......或者暴力破解整个事情,然后迭代 matches() 直到已经没有了,但我想知道是否有更优雅的方法来完成这项工作。

offset 添加到 theRange 的开头。来自 method reference:

offset: The offset to be added to the location of the result in the string.

override func replacementString(for result: NSTextCheckingResult,
                                in string: String,
                                offset: Int,
                                template templ: String) -> String {

    var theRange = result.range(at: 0)
    theRange.location += offset

    let theSubStr = NSString(string: string).substring(with: theRange)
    return super.replacementString(for: result,
                                   in: string,
                                   offset: offset,
                                   template: self.magic(theSubStr))
}