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

时间:2018-04-17 23:19:42

标签: swift4 nsregularexpression swift4.1

我尝试编写一些代码,我在字符串中迭代正则表达式匹配并对匹配运行操作,将其替换为操作的结果。我遇到了问题,我的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: "$0")
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()直到没有&#39任何左翼,但我想知道是否有更优雅的方式来完成这项工作。

1 个答案:

答案 0 :(得分:1)

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

  

offset:要添加到字符串中结果位置的偏移量。

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))
}