Pegjs: 能够指定重复计数(如在正则表达式中)

创建于 2011-08-11  ·  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\}

feature

最有用的评论

我也喜欢重复计数。 但我建议使用稍微不同的语法。 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 ,不使用分隔符的问题在于它可能会扼杀语言语法的演变。

例如,如果我们想在以后使用逗号来表示其他东西,那么我们现在就会遇到到处都是语法冲突的问题。 将其限制在<>括号内会大大减少逗号和数字的表面积。

另外,人们习惯于在 RegExps 中使用{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。

这是问题的简化版本:

KK4TesRandomKK10TestATestBRandom

逻辑:

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

KK是标记字符串的指示器。 以下数字(此处410 )是字符串的长度。 然后是字符串本身(这里是TestTestATestB )。 字符串不会被任何可预测的模式终止。 我基本上必须使用长度信息。 我想说这是二进制文件格式中的一种常见模式,但是可以用当前的语法进行解析吗?

谢谢你。

我在我的分支range-dynamic-boundary中实现了这样的东西。 语法看起来像这样:

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

@Mingun哇! 这就像一个魅力! 非常感谢您的实施和简短的示例。 我做了一些测试,效果很好。 我希望你的拉取请求被主人接受。

我也喜欢重复计数。 但我建议使用稍微不同的语法。 Pegasus几乎与 pegjs 相同,仅适用于 C#。 见这里: https ://github.com/otac0n/Pegasus/wiki/Syntax-Guide#expressions

他们使用这个实现了这个功能: d<3> e<2,> f<1,5>

人们对此有什么解决办法? 我现在才刚接触 PEGjs,所以也许我想用锤子拧螺丝,但我只是想匹配 1 到 6 位数字:)

我正在使用我自己的实现(有关语法,请参阅#267,最终解决方案支持数字、变量和代码块作为边界),我将很快为Peggy准备 PR(维护的 PEG.js 分支的更名)

此页面是否有帮助?
0 / 5 - 0 等级