swift regex可在联机工具中使用,但与NSRegularExpression不一致

svmlkihl  于 2022-12-10  发布在  Swift
关注(0)|答案(1)|浏览(95)
do {
    // initialization failed, looks like I can not use "\\" here
    let regex = try NSRegularExpression.init(pattern: "(?<!\\)\n")

    let string = """
    aaabbb
    zzz
    """
    
    // expect "aaabbb\nzzz"
    print(regex.stringByReplacingMatches(in: string, options: [], range: NSMakeRange(0, string.count), withTemplate: "\\n"))
} catch let error {
    print(error)
}

在这里,我想将字符串中的“\n”替换为“\n”,但在开头就失败了,错误消息为

// NSRegularExpression did not recognize the pattern correctly.
Error Domain=NSCocoaErrorDomain Code=2048 "The value “(?<!\)
” is invalid." UserInfo={NSInvalidValue=(?<!\)
}

这个正则表达式已经在regular expression 101中测试过了,所以它是正确的,只是由于某种原因在Swift中不起作用。
我该怎么做?

a0zr77ik

a0zr77ik1#

根据Larme的评论:
在Swift中,字符串中的\(双反斜杠)表示“有一个”,正如你在错误中看到的,你有(?<!\),但它意味着你正在转义结束的),所以你有一个丢失的结束的)。我想你应该写为then "(?<!\\\\)\n"
我终于弄明白了是怎么回事,以及如何解决它。
问题是反斜杠
在Swift中,双引号内的反斜杠将被视为转义序列,如下所示

// won't compile
// error: Invalid escape sequence in literal
let regex = try NSRegularExpression.init(pattern: "(?<!\)\n")

如果我们再加一个反斜杠,它是工作吗?
否,因为这两个反斜杠将被视为即将结束的单个转义符)。

// compile but get a runtime error
let regex = try NSRegularExpression.init(pattern: "(?<!\\)\n")

因此出现运行时错误

NSRegularExpression did not recognize the pattern correctly.
Error Domain=NSCocoaErrorDomain Code=2048 "The value “(?<!\)
” is invalid." UserInfo={NSInvalidValue=(?<!\)

为了说明我们需要的是一个反斜杠,我们实际上需要4个反斜杠

let regex = try NSRegularExpression.init(pattern: "(?<!\\\\)\n")

前两个反斜杠表示转义字符,后两个反斜杠表示一个文字反斜杠。
这些看起来很麻烦。

更好的方法

幸运的是,从Swift 5开始,我们可以使用一对#来实现这一点

// works like in online tool
let regex = try NSRegularExpression.init(pattern: #"(?<!\\)\n"#)

另一件事
值得注意的是,正则表达式的初始化并不是唯一需要特殊处理的事情

// withTemplate
print(regex.stringByReplacingMatches(in: string, options: [], range: NSMakeRange(0, string.count), withTemplate: #"\\n"#))

// As a comparison, this is OK
print(string.replacingOccurrences(of: "\n", with: "\\N"))

相关问题