Было бы полезно, если бы грамматика 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\}
Я не буду реализовывать эту функцию.
Основная причина в том, что в грамматике 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, который поддерживается)
Самый полезный комментарий
Я бы тоже хотел количество повторений. Но я бы предложил немного другой синтаксис. Pegasus почти идентичен pegjs, только для C#. См. здесь: https://github.com/otac0n/Pegasus/wiki/Syntax-Guide#expressions
И они реализовали эту функцию, используя это:
d<3> e<2,> f<1,5>