当表情符号存在时,使用NSRegularExpression会产生不正确的范围

时间:2017-09-29 19:00:02

标签: ios swift string emoji

我正在尝试从用户提供的字符串中解析出“@mentions”。正则表达式本身似乎找到它们,但是当存在表情符号时,它提供的范围是不正确的。

let text = " @joe "
let tagExpr = try? NSRegularExpression(pattern: "@\\S+")
tagExpr?.enumerateMatches(in: text, range: NSRange(location: 0, length: text.characters.count)) { tag, flags, pointer in
    guard let tag = tag?.range else { return }

    if let newRange = Range(tag, in: text) {
        let replaced = text.replacingCharacters(in: newRange, with: "[email]")
        print(replaced)
    }
}

运行时 tag =(位置:7,长度:2)

打印出来 [email]oe

预期结果是 [email]

1 个答案:

答案 0 :(得分:2)

NSRegularExpression(以及涉及NSRange的任何内容)对UTF16计数/索引进行操作。就此而言,NSString.count也是UTF16计数。

但是在您的代码中,您告诉NSRegularExpression使用text.characters.count的长度。这是组合字符的数量,而不是UTF16计数。您的字符串" @joe "有9个组成字符,但有12个UTF16代码单元。因此,您实际上是在告诉NSRegularExpression仅查看前9个UTF16代码单元,这意味着它忽略了尾随"oe "

修复方法是通过length: text.utf16.count

let text = " @joe "
let tagExpr = try? NSRegularExpression(pattern: "@\\S+")
tagExpr?.enumerateMatches(in: text, range: NSRange(location: 0, length: text.utf16.count)) { tag, flags, pointer in
    guard let tag = tag?.range else { return }

    if let newRange = Range(tag, in: text) {
        let replaced = text.replacingCharacters(in: newRange, with: "[email]")
        print(replaced)
    }
}