正则表达式unicode在swift中不起作用

时间:2018-03-29 17:28:59

标签: swift regex unicode emoji nsregularexpression

let regex1 = "(\\ud83d\\udc68)"
let regex2 = "(\\ud83d[\\udc68-\\udc69])"

"".capturedGroupsFull(forRegex: regex1)
// returns 1 match: [(.0 "", .1 {0, 2})]
"".capturedGroupsFull(forRegex: regex2)
// returns nil

为什么第一行返回一个匹配而第二行不匹配?

  • 两个正则表达式在regex101上都能正常工作(例如设置为 javascript并使用第二个正则表达式作为(\ud83d[\udc68-\udc69]))。
  • 我是 使用Swift 4.0。
  • 此正则表达式"(\\ud83d[\\udc68])"也将 在Playground中测试时返回nil

您可以在下面找到我用来检索匹配项的完整代码。

extension String {
    func capturedGroupsFull(forRegex regex: String) -> [(String, NSRange)]? {
        let expression: NSRegularExpression
        do {
            expression = try NSRegularExpression(pattern: regex, options: [.caseInsensitive])
        } catch {
            return nil
        }
        let nsString = self as NSString
        let matches = expression.matches(in: self, options: [], range: NSRange(location:0, length: nsString.length))
        guard let match = matches.first else { return nil }
        var results = [(String, NSRange)]()
        for match in matches {
            let range = match.range
            let matchedString = nsString.substring(with: range)
            results.append((matchedString, range))
        }
        return results
    }
}

1 个答案:

答案 0 :(得分:1)

为什么第一行返回一个匹配而第二行不匹配?

如前所述,NSRegularExpression适用于Unicode代码点,(正常)JavaScript正则表达式适用于UTF-16代码单元。

某些模式,如"\\ud83d\\udc68",由有效的代理项对组成,可以针对单个Unicode代码点U + 1F468进行优化,但此功能没有详细记录,因此您不应该依赖它,正如您在示例"(\\ud83d[\\udc68])"中找到的那样。

我建议不要在\uhhhh上使用代理对,但对非BMP字符使用\UHHHHHHHH(或\x{hhhh})。

let regex1 = "(\\U0001F468)" //or "(\\x{1F468})"
let regex2 = "([\\U0001F468-\\U0001F469])" // or "([\\x{1F468}-\\x{1F469}])"

"".capturedGroupsFull(forRegex: regex1)
// -> [(.0 "", .1 {0, 2})]
"".capturedGroupsFull(forRegex: regex2)
// -> [(.0 "", .1 {0, 2})]

最近的JavaScript正则表达式接受u选项以使其与Unicode代码点一起使用,请尝试以下操作:

/(\u{1F468})/u
/([\u{1F468}-\u{1F469}])/u

您可以使用JavaScript语法轻松测试正则表达式模式,并将其转换为NSRegularExpression语法,并将\u替换为\x(并删除//u )。