2016-09-20 6 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, мы можем использовать lookahead, чтобы продолжать потребление, если у нас есть ); впереди.

Таким образом, решение:

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

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

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

В TextUntilTerminator Нетерминальные потребляет в то время как HaveTerminatorAheadматчей без потребляющих его (просмотр вперед, тем & символов). Затем он потребляет один символ. Он делает это до тех пор, пока не узнает, что мы достигли финала ); на входе.

HaveTerminalAhead non-terminal прост: он проверяет, есть ли один символ впереди, и, если это так, гарантирует, что после него будет по крайней мере один );. Мы также используем негативный взгляд !, чтобы остановиться на первом );, который мы видим (не используйте его, чтобы воспроизвести оригинальную проблему).

Этот ПЭГ затем воспроизводит поведение предложенного регулярного выражения.

+0

Ницца, он работает! И я тоже кое-что узнал =) Спасибо большое! – mottosson

+0

Обратите внимание, что если вы используете это в большей грамматике, вы, вероятно, должны добавить другой вид взгляда, чтобы ограничить проверку. В приведенном выше коде предполагается, что вы хотите использовать последний ');' на входе, который может быть не желательным, если вы хотите совместить вещи _beyond_ a 'Text'. – paulotorrens

+0

Я буду читать файлы с несколькими строками такого рода, но, возможно, я мог бы просто добавить \ n к грамматике, чтобы учесть это? – mottosson