匹配未转义的平衡对分隔符

如何匹配未被反斜杠转义的平衡对分隔符(本身不会被反斜杠转义)(无需考虑嵌套)? 例如,使用反引号,我尝试了这个,但转义的反引号不能像转义那样工作。

regex = /(?!<\\)`(.*?)(?! $1: "how\\" # expected "how\\` are" 

上面的正则表达式不考虑反斜杠转义的反斜杠,而是在反引号前,但我想。

StackOverflow如何做到这一点?

这样做的目的并不复杂。 我有文档文本,其中包括内联代码的反引号符号,就像StackOverflow一样,我希望在HTML文件中显示内联代码,并使用一些span材料。 没有嵌套,但是逃逸的反引号或逃逸的反斜杠可能出现在任何地方。

Lookbehind是每个人都会想到这个问题的第一件事,但它是错误的工具,即使在支持不受限制的外观的.NET等版本中也是如此。 你可以破解一些东西,但即使在.NET中它也会很难看。 这是一个更好的方法:

 `[^`\\]*(\\.[^`\\]*)*` 

第一部分从开头分隔符开始,吞噬任何不是分隔符或反斜杠的东西。 如果下一个字符是反斜杠,它将消耗该字符以及跟随它的字符,无论它是什么。 它可能是分隔符,另一个反斜杠,或其他任何东西,无所谓。

它根据需要重复这些步骤,并且既不是[^`\\]也不是\\. 可以匹配,下一个字符必须是结束分隔符。 或者字符串的结尾,但我假设输入结构良好。 但如果它没有很好地形成,这个正则表达式将很快失败。 我提到,由于这种其他方法,我看到了很多:

 `(?:[^`\\]+|\\.)*` 

这适用于格式良好的输入,但是如果从样本输入中删除最后一个反引号会发生什么?

 "hello `how\` are you" 

根据RegexBuddy的说法,在遇到第一个反引号之后,这个正则表达式在它放弃并报告失败之前执行了9,252个不同的操作(或步骤); 我的失败了十步。

编辑要仅在分隔符内提取par,请将该部分包装在捕获组中。 你仍然需要手动删除反斜杠。

 `([^`\\]*(?:\\.[^`\\]*)*)` 

我还将其他组改为非捕获组,我应该从一开始就完成。 我不会避免虔诚地捕捉,但如果你使用它们来捕获东西,你使用的任何其他组都应该是非捕获的。

编辑我想我一直在读这个问题。 在StackOverflow上,如果要在内联代码段或注释中包含文字反引号,则使用三个反引号作为分隔符,而不只是一个。 由于不需要逃避反引号,因此您也可以忽略反斜杠。 您的正则表达式可能会变得如此简单:

 ```(.*?)``` 

处理错误分隔符的可能性,您使用相同的基本技术:

 ```([^`]*(?:`(?!``)[^`]*)*)``` 

这就是你要追求的吗?


顺便说一句,这个答案与@ nneonneo上面的评论并不矛盾。 这个答案没有考虑匹配发生的背景。 它是在程序或网页的源代码中吗? 如果是,匹配发生在注释或字符串文字中吗? 我怎么知道我发现的第一个反击没有逃脱? 正则表达式对它们运行的​​背景一无所知; 这就是解析器的用途。

如果你不需要嵌套,那么正则表达式确实是一个合适的工具。 例如,编程语言的Lexers使用正则表达式来标记字符串,而字符串通常允许自己的分隔符作为转义内容。 比这更复杂的东西可能需要一个完整的解析器。

“通用公式”用于匹配转义字符( \\. )或任何有效作为内容但不需要转义[^{list of invalid chars}][^{list of invalid chars}] )。 一个“天真”的解决方案是用or或| )加入它们,但是对于一个更有效的变体,请参阅@AlanMoore的答案 。

下面显示了完整的示例,有两种变体:第一个假设比反斜杠应用于在字符串转义,第二个假定文本中任何地方的反斜杠都会转义下一个字符。

 `((?:\\.|[^`\\])*)` (?:\\.|[^`\\])*`((?:\\.|[^`\\])*)` 

这里和这里的工作示例。 但是,正如@nneonneo评论(并且我赞同),正则表达式并不意味着要完成一个完整的解析,所以如果你想让它们正常工作你最好保持简单(你想在文本中找到一个标记,或者你是否想要划分它已经知道它从哪里开始?这个问题的答案对决定哪种策略最适合你的情况很重要。