2016-09-20 51 views
1

我試圖在最後用分號捕捉到一些文本。 (。*)PEG.js獲取(和)之間的任何文本;

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

我已經試過這

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

但似乎將包括最後一個);之前「);」我得到的錯誤:

Expected ");" or any character but end of input found

問題是,文本可以包含「);」所以我想要最外面的);在線路結束時進行決定。

這個正則表達式\((.*)\);做我想做的,但我怎麼能在PEG.js中做同樣的事情?我不想在結果中包含外部括號和分號。

這似乎應該是相當容易,如果你知道自己在做什麼= P

+0

我有。找不到我正在尋找的東西。或者,也許我不明白。如果您知道文檔中的位置,請注意,如果您能告訴我在哪裏。 – mottosson

回答

5

所以,問題是,一個PEG是確定性的,而正則表達式是不是。所以一旦接受了一些輸入,PEG就不會回溯。然後我們可以模擬你想要的語義。既然你說正則表達式\((.*)\);做你想做的,我們可能會把它翻譯成PEG。

這個正則表達式有什麼作用?它消耗所有字符直到輸入結束,然後保持回溯直到看到);,即它消耗最後可能的);

爲了使這項工作與PEG,我們可能會使用前瞻來繼續消費,如果我們有一個);提前。

因此,一個解決方案是:

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

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

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

TextUntilTerminator非末端消耗而HaveTerminatorAhead比賽而不消耗它(先行,則&符號)。然後它消耗一個單個字符。它會這樣做,直到它知道我們已經在輸入上達到最終的);

HaveTerminalAhead非終端很簡單:它驗證前面是否有一個字符,如果是,則保證後面至少有一個);。我們也使用負面預測!停止在我們看到的第一個);(避免消耗它,這會重現您的原始問題)。

然後,這個PEG再現了你所建議的正則表達式的行爲。

+0

不錯,它的作品!我也學到了一些東西=)非常感謝! – mottosson

+0

請注意,如果您在更大的語法中使用此語法,則可能應該添加另一種預測來限制檢查。上面的代碼假設你想在輸入上使用最後一個'';',如果你想匹配_beyond_文本''這可能不是期望的行爲。 – paulotorrens

+0

我會用這種多行讀取文件,但也許我可以在文法中添加一個\ n來考慮這個問題? – mottosson

相關問題