3

I'm trying to write some code where I iterate over regex matches in a string and run an operation on the match, replacing it with the result of the operation. I'm running into problems though, where inside my replacementString() override the supplied range of the 2nd and subsequent matches don't match the locations in the source string if the previous replacement strings aren't precisely the same length as their original match substring.

I've constructed a simple example to demonstrate the problem.

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)

The output I expect from this is:

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

But, the output I get is this:

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

The final substitution gets put in the right place, but since I'm trying to run an operation on the matched text, I need the right substring to show up in my magic() method.

I can try to track the difference in the matches and the resulting replacement string and modify each range by the +/- ... or brute force the whole thing and just iterate over matches() until there aren't any left, but I'm wondering if there's a more elegant way to make this work.

4

1 回答 1

3

添加offsettheRange. 从方法参考

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))
}
于 2018-04-19T12:18:41.813 回答