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

时间:2012-10-25 03:08:27

标签: ruby regex

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

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

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

StackOverflow如何做到这一点?

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

2 个答案:

答案 0 :(得分:6)

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

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

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

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

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

这适用于结构良好的输入,但如果从样本输入中删除最后一个反引号会怎样?

"hello `how\` are you"

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

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

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

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

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

```(.*?)```

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

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

这就是你要追求的吗?


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

答案 1 :(得分:2)

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

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

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

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

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

工作示例herehere。然而,正如@nneonneo评论(并且我赞同),正则表达式并不意味着要做一个完整的解析,所以如果你想让它们正确运行你最好保持简单(你想要找到文本中的一个标记,或者你想分界它已经知道它开始的位置?这个问题的答案对于确定哪种策略最适合你的情况很重要。