5

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

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

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

StackOverflow 如何做到这一点?

这样做的目的并不复杂。我有文档文本,其中包括内联代码的反引号,就像 StackOverflow 一样,我想在 HTML 文件中显示它,内联代码装饰有一些跨度材料。不会有嵌套,但转义的反引号或转义的反斜杠可能会出现在任何地方。

4

2 回答 2

6

对于这类问题,Lookbehind 是每个人首先想到的,但它是错误的工具,即使在 .NET 这样支持不受限制的lookbehinds 的风格中也是如此。你可以破解一些东西,但它会很丑陋,即使在 .NET 中也是如此。这是一个更好的方法:

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

第一部分从开始的分隔符开始,吞噬任何不是分隔符或反斜杠的东西。如果下一个字符是反斜杠,它会使用该反斜杠及其后面的字符,无论它可能是什么。它可以是分隔符、另一个反斜杠或其他任何东西,没关系。

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

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

这适用于格式正确的输入,但是如果您从示例输入中删除最后一个反引号会发生什么?

"hello `how\` are you"

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

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

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

我还将另一组更改为非捕获,我应该从一开始就这样做。我不会避免虔诚地捕获,但是如果您使用它们来捕获东西,那么您使用的任何其他组都应该是非捕获的。

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

```(.*?)```

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

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

这就是你所追求的吗?


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

于 2012-10-25T06:10:50.040 回答
2

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

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

完整的示例如下所示,有两种变体:第一个假设反斜杠用于在字符串内部转义,第二个假设反斜杠在文本中的任何位置转义下一个字符。

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

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

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

于 2012-10-25T05:37:59.113 回答