4

我试图在最后用分号捕捉一些文本。

例子:(in here there can be 'anything' !"#¤);); any character is possible);

我试过这个:

Text
 = "(" text:(.*) ");" { return text.join(""); }

但似乎 (.*) 将包括最后一个 ); 前 ”);” 确实,我得到了错误:

预期的 ”);” 或找到输入结尾以外的任何字符

问题是文本可以包含“);” 所以我想要最外面的);决定线路何时结束。

这个正则表达式\((.*)\);做我想要的,但我怎么能在 PEG.js 中做同样的事情呢?我不想在结果中包含外括号和分号。

如果您知道自己在做什么,这似乎应该很容易 =P

4

1 回答 1

11

所以,关键是 PEG 是确定性的,而正则表达式不是。因此,一旦 PEG 接受了一些输入,它就不会回溯。然后我们可以模拟你想要的语义。既然您说正则表达式可以满足\((.*)\);您的要求,我们可能会将其转换为 PEG。

这个正则表达式有什么作用?它消耗所有字符直到输入结束,然后继续回溯,直到它看到 a );,即它消耗最后一个可能的);

为了使这项工作与 PEG 一起工作,我们可能会使用前瞻来继续消费,如果我们有);提前的话。

所以,一个解决方案是:

Text
 = "(" text:TextUntilTerminator ");" { return text.join(""); }

TextUntilTerminator
 = x:(&HaveTerminatorAhead .)* { return x.map(y => y[1]) }

HaveTerminatorAhead
 = . (!");" .)* ");"

TextUntilTerminator非终端在匹配时消耗而不HaveTerminatorAhead 消耗它(前瞻,&符号)。然后它消耗一个字符。它会这样做,直到它知道我们已经达到了);输入的最终结果。

HaveTerminalAhead终结符很简单:它验证前面是否有一个字符,如果有,保证后面至少有一个);。我们还使用负前瞻在我们看到!的第一个地方停止);(避免使用它,这会重现您的原始问题)。

然后,这个 PEG 再现了您建议的正则表达式的行为。

于 2016-09-21T12:55:10.950 回答