Pegjs: Возможность указать количество повторений (как в регулярных выражениях)

Созданный на 11 авг. 2011  ·  22Комментарии  ·  Источник: pegjs/pegjs

Было бы полезно, если бы грамматика PEG.js позволяла использовать что-то вроде выражений диапазона базовых регулярных выражений POSIX. Например:

  • "a"\{1,7\}

соответствует a , aa , ..., aaaaaaa

  • "a"\{0,1\}

соответствует пустой строке и a

  • "a"\{,6\}

соответствует строке, содержащей до (включительно) шести символов a

  • "a"\{6,\}

соответствует строке из шести или более a

  • "a"\{3\}

соответствует только aaa , что эквивалентно "a"\{3,3\}

Самый полезный комментарий

Я бы тоже хотел количество повторений. Но я бы предложил немного другой синтаксис. Pegasus почти идентичен pegjs, только для C#. См. здесь: https://github.com/otac0n/Pegasus/wiki/Syntax-Guide#expressions

И они реализовали эту функцию, используя это: d<3> e<2,> f<1,5>

Все 22 Комментарий

Я не буду реализовывать эту функцию.

Основная причина в том, что в грамматике PEG.js нет места для синтаксиса {m,n} — фигурные скобки уже взяты для действий, и я не хочу использовать обратную косую черту, как вы предлагаете (они уродливы и несовместимы с регулярными выражениями Perl, которые сейчас наиболее часто используются, а также источником другого синтаксиса PEG.js) или другими разделителями (это может сбивать с толку).

По моему опыту, такое ограниченное повторение встречается в основном в «лексических» частях грамматики (правила вроде color = "#" hexdigit hexdigit hexdigit hexdigit hexdigit hexdigit ) и не так часто. Я думаю, что можно просто использовать последовательности выражений и существующие операторы повторения ( * , + , ? ).

Я пересмотрел и снова поднимаю этот вопрос. Похоже, пользователям очень нужна возможность указывать произвольное количество повторений.

Я хотел бы избежать синтаксиса {m,n} , подобного регулярному выражению, потому что { и } уже используются для действий, и их повторное использование может создать двусмысленность. В настоящее время я думаю о чем-то вроде этого:

"foo" @ 1..10   // repeat 1 to 10 times
"foo" @ 1..     // repeat at least once
"foo" @ ..10    // repeat at most 10 times

Самый большой вопрос заключается в том, какими должны быть разделительные символы и как размечать диапазоны.

Что касается разделительного символа, @ мне кажется хорошим. Я рассматривал % и # , но, на мой взгляд, первый уже связан с интерполяцией строк (например, в Python), а второй — с комментариями (на разных языках). Я также думаю о том, чтобы полностью пропустить разделитель:

"foo" 1..10   // repeat 1 to 10 times
"foo" 1..     // repeat at least once
"foo" ..10    // repeat at most 10 times

Что касается разметки диапазона, я черпал вдохновение в Ruby. Я также думал о - , но это слишком похоже на знак минус. С другой стороны, Python-подобный : мне тоже нравится.

Я не уверен насчет полуоткрытых диапазонов. Может быть, было бы лучше разметить их, используя + и - , вот так:

"foo" @ 1+    // repeat at least once
"foo" @ 10-   // repeat at most 10 times

Любые идеи или комментарии?

Действительно здорово, что вы планируете поддерживать эту функцию!

Мне нравится ваше (по умолчанию) предложение:
"foo" @ 1..10 // повторить от 1 до 10 раз
"foo" @ 1.. // повторить хотя бы один раз
"foo" @ ..10 // повторить не более 10 раз

Мне не нравится синтаксис +/- для полуоткрытых диапазонов, синтаксис с двумя точками гораздо более интуитивно понятен и читабелен IMO.

Единственное, о чем я подумал, так это об использовании «#» против «@», потому что IMO «#» естественно подразумевает числа/счет, тогда как «@» естественно подразумевает ссылку, поэтому «#» может быть немного более интуитивно понятным и читаемым. (и, возможно, вы могли бы использовать «@» в будущем для чего-то?). Но это действительно незначительная проблема, и я был бы доволен синтаксисом "@".

Ваше здоровье!

Небольшой комментарий: я думаю, что @ и % — лучший выбор, чем # , потому что подсветка синтаксиса не поддерживает грамматику PEG.js, особенно те, которые пытаются угадать синтаксис (например, подсветка кода Stack Overflow), скорее всего, интерпретирует # как начало комментария, заставляя его отображаться — раздражающе — с этой точки до EOL в «цвете комментария». Это предпочтение основано не на логике и рассуждениях, конечно, а на прагматизме.

Как насчет специального случая для {num, num} ? Что БУДЕТ означать повторение, поскольку { , num} и { num, } не являются допустимым кодом js, а {num, num} и { num } бессмысленны.

Они вряд ли будут иметь смысл, даже если действие происходит на других языках.

Мне нравятся эти варианты из предложенных (но это конечно на ваше усмотрение, ведь вы же автор :) ):

// why we need separator, anyway? for me it looks very cool and simple to understand
"foo" 1..10   // repeat 1 to 10 times
"foo" 1..     // repeat at least once
"foo" ..10    // repeat at most 10 times

или

"foo"@1..10   // repeat 1 to 10 times
"foo"@1..     // repeat at least once
"foo"@..10    // repeat at most 10 times

но второй менее предпочтителен

идея x..y / ..y / x.. выглядит очень круто, так как .. благодаря ей выглядит как непротиворечивый оператор.

+/- для меня не подходят, потому что они сбивают с толку и становятся дополнительными операторами над ..+ уже используется)

Думая об этом снова. Будут ли они работать?

'foo'<1,5>
'foo'< ,3>
'foo'<2, >

поскольку < и > в настоящее время не используются грамматикой

:+1: по-моему, это выглядит хорошо.

конечно, <,3> эквивалентно <0,3> , поэтому мы можем просто потребовать минимальное число. Это согласуется с тем, что ECMA сделал для регулярных выражений JavaScript.

Мне нравится <,> . Но я бы также предложил использовать <3> так же, как <3,3> .

Я согласен, синтаксис <> должен максимально точно соответствовать поведению {} в RegExp.

Если я не ошибаюсь, нет необходимости добавлять какой-либо разделитель, если только вы не хотите разрешить имена переменных в диапазонах.

foo 1,2 fighter
bar ,3 tender
baz 4, lurhmann
qux 5 quux

все однозначны.

@pygy проблема с отсутствием разделителя заключается в том, что он потенциально подавляет эволюцию синтаксиса языка.

Например, если бы мы позже захотели использовать запятую для чего-то другого, у нас теперь бы повсюду возникали проблемы с синтаксическими коллизиями. Ограничение его скобками <> существенно уменьшает площадь запятых и чисел.

Кроме того, люди все равно привыкли использовать стиль {1,6} в регулярных выражениях.

Я не особо разбираюсь в синтаксисе, но мне нужна эта функция, и было бы здорово, если бы выражение можно было использовать в качестве значения диапазона.

Мой пример использования: анализ литералов в ответах сервера IMAP, которые выглядят как {42}\r\n... , где 42 — это количество символов после новой строки, которые представляют строку (показанную здесь как многоточие). Поскольку для литерала IMAP нет конечного разделителя, подсчет символов — единственный способ проанализировать этот ответ.

Как насчет переменных в ограничениях? Это очень полезно для сообщений с заголовком, содержащим его длину. Например, грамматика

  = len:number message:.<len,len> .* {return message;}
number
  = n:[0-9] {return parseInt(n);}

должен разобрать

4[__] -> ['[', '_', '_', ']']
4[___] -> ['[', '_', '_', '_']
4[_] -> Error: expected 4 chars, got 3

Это полезно для многих протоколов.

Можно использовать этот синтаксис:
expression |min,max| , то для правил шаблона можно использовать угловые скобки.

Вы все еще рассматриваете возможность реализации этого?
Как насчет чего-то похожего на диапазоны ABNF ?

exp *     // 0 or more times
exp 1*    // at least once
exp *10   // up to 10 times
exp 1*10  // 1 to 10 times

Привет. У меня есть сложный формат файла для анализа. Наполовину двоичный, наполовину ASCII.

Вот упрощенная версия проблемы:

KK4TesRandom или KK10TestATestBRandom

Логика:

<StringIndicator><StringLength><String><otherStuff>

KK — это индикатор для обозначения строки. Следующие цифры (здесь 4 и 10 ) являются длиной строки. Затем сама строка (здесь Test и TestATestB ). Строка не заканчивается каким-либо предсказуемым шаблоном. Я в основном должен использовать информацию о длине. Я бы сказал, что это распространенный шаблон в двоичных форматах файлов, но можно ли выполнить синтаксический анализ с текущей грамматикой?

Спасибо.

Я реализую такую ​​​​вещь в своей ветке ranges-dynamic-boundary . Грамматика будет выглядеть так:

start = len:nx data:.|len| { return data; };
nx = n:$[0-9]+ { return parseInt(n, 10); };

@Мингун вау! Это работает как шарм! Большое спасибо за вашу реализацию и короткий пример. Я сделал несколько тестов, и это работает потрясающе. Я надеюсь, что ваш запрос на включение будет принят мастером.

Я бы тоже хотел количество повторений. Но я бы предложил немного другой синтаксис. Pegasus почти идентичен pegjs, только для C#. См. здесь: https://github.com/otac0n/Pegasus/wiki/Syntax-Guide#expressions

И они реализовали эту функцию, используя это: d<3> e<2,> f<1,5>

Какие люди обходятся для этого? Я только сейчас знакомлюсь с PEGjs, поэтому, возможно, я пытаюсь повернуть винт молотком, но я просто пытаюсь сопоставить цифры от 1 до 6 :)

Я использую свою собственную реализацию (см. # 267 для синтаксиса, окончательное решение поддерживает числа, переменные и блоки кода в качестве границ), и я скоро подготовлю PR для Peggy (ребрендинг форка PEG.js, который поддерживается)

Была ли эта страница полезной?
0 / 5 - 0 рейтинги