【问题标题】:Negative lookbehind to not match escaped characters, fails on escaped backslash与转义字符不匹配的负向后看,在转义反斜杠上失败
【发布时间】:2019-08-05 15:49:04
【问题描述】:

假设我想在任何分隔符处拆分字符串,但不是转义符,我通常可以使用否定的lookbehind和string.split(regex)。

例如:

const regex = /(?<!\\)\,/;
'abc,def'.split(regex); 
'abc\\,def'.split(regex); 

abc,def 中的, 处拆分,但不在abc\,def 中拆分。这很好!

但是,如果分隔符本身是反斜杠,则负向查找似乎无法按预期工作:

const regex = /(?<!\\)\\/;
'abc\\def'.split(regex); 
'abc\\\\def'.split(regex); 

abc\defabc\\def 中的第一个\ 处拆分。

我天真地以为否定的后视不会匹配\ 前面有一个\

见:https://regex101.com/r/ozkZR1/1

如何在任何不与反斜杠或换行符等特殊字符分开的非转义字符上实现 string.split(regex)(也应该能够转义它们)?

【问题讨论】:

标签: javascript regex typescript escaping negative-lookbehind


【解决方案1】:

简单的解决方案

如果您的分隔符与您的分隔符相同,您可以在分隔符之后的负前瞻,在负前瞻的顶部:

/(?<!\\)\\(?!\\)/

注意事项

这种方式存在很多问题,不建议用正则表达式解决,尤其不建议让分隔符和转义符相同。

  • 使用 , 作为分隔符,字段末尾的文字字符会欺骗正则表达式,例如,abc\\,def 不会被拆分。
  • 使用\ 作为分隔符和转义字符,您不能有空字段:abc,,def 将是三个字段,包括一个空字段,但 abc\\def 将只是一个字段。
  • abc\\\def 呢?在第一个字段的末尾或第二个字段的开头是否有文字 \?无论哪种方式,我的正则表达式都不会分裂。

如果您愿意禁止在边界字​​面上使用转义字符,并且不允许空字段,那么当转义和分隔符相同时,我的正则表达式将起作用,而在另一种情况下,您的正则表达式将起作用。

否则,我会推荐一个不同的解决方案,您从左到右解析字符串,在遇到转义时解释转义,并在看到未转义的分隔符时拆分,以便正确拆分 abc\\,def

【讨论】:

    【解决方案2】:

    解决办法是逆向操作:

    我可以查找分隔字符序列,而不是查找分隔符。因此,如果是 , 分隔符,我会查找:((\\,)|[^,])([^,]*?(\\,)?)*:转义逗号或非逗号字符,后跟任意数量(可能为空)的非逗号组(不情愿,所以它不会捕获转义的\),后跟可选的转义逗号。

    let separator = ','; // get from sanitized input
    separator = separator === '\\' ? '\\\\' : separator;
    const groups = new RegExp(`((\\\\${separator})|[^${separator}])([^${separator}]*?(\\\\${separator})?)+`, 'g');
    let columns = line.match(groups);
    

    这适用于 ,\ 作为分隔符,不会分别在 \,\\ 上拆分。

    该表达式中最难的部分是正确地进行所有转义。

    【讨论】:

    • 话虽如此,这当然会留下一些漏洞。基本问题仍然是很难决定正则表达式引擎,\\x 是转义反斜杠后跟 x 还是反斜杠后跟转义 x。例如,这个正则表达式将匹配整个 xx\\,yy 即使它应该找到转义反斜杠后面的逗号,它严格从左到右工作。
    猜你喜欢
    • 1970-01-01
    • 2015-05-19
    • 1970-01-01
    • 1970-01-01
    • 2017-06-24
    • 2012-07-25
    • 2021-12-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多