Parslet:识别除给定关键字之外的任何内容

时间:2015-03-04 10:02:33

标签: ruby regex parslet

我试图为Handlebars编写一个Ruby / Parslet解析器,但是我遇到了{{ else }}关键字。 为了解释那些不使用Handlebars的人的简要说明,if / else以这种方式编写:

{{#if my_condition}}
  show something
{{else}}
  show something else
{{/if}}

但它变得棘手,因为内联和帮助程序可以使用相同的语法,例如:

Name: {{ name }}
Address: {{ address }}

所以我首先制定了一条规则来识别替代品:

rule(:identifier)  { match['a-zA-Z0-9_'].repeat(1) }
rule(:path)        { identifier >> (dot >> identifier).repeat }

rule(:replacement) { docurly >> space? >> path.as(:item) >> space? >> dccurly}

匹配{{name}}{{people.name}}之类的内容。 问题当然是也与{{ else }}块匹配。以下是我编写规则以匹配if / else块的方法:

rule(:else_kw) {str('else')}
rule(:if_block) {
  docurly >>
  str('#if') >>
  space >>
  path.as(:condition) >>
  space? >>
  dccurly >>
  block.as(:if_body) >>
  (
    docurly >>
    else_kw >>
    dccurly >>
    block.as(:else_body)
  ).maybe >>
  docurly >>
  str('/if') >>
  dccurly
}

(注意:docurly是{{,dccurly是}},阻止可以是或多或少的任何东西)

所以我现在需要重写`identifier``rule,以便它匹配任何单词,但不是"否则"。

提前致谢, 文森特

2 个答案:

答案 0 :(得分:0)

执行此操作的一种方法是使用absent?前瞻修饰符。如果原子或规则foo.absent?此时匹配,foo将匹配,并且不会消耗任何输入。

有了这个,您可以将identifier规则写为

rule(:identifier)
    { (else_kw >> dccurly).absent? >> match['a-zA-Z0-9_'].repeat(1) }

答案 1 :(得分:0)

这取决于您尝试匹配的语法。如果您不在{{if}} {{/if}}对内,应将{{else}}视为有效标识符还是语法错误?如果您有a.else.b的路径应该有效吗?

如果a.else.b无效,您可以执行以下操作:

rule(:identifier)
    { (else_kw).absent? >> match['a-zA-Z0-9_'].repeat(1) | else_kw >> match['a-zA-Z0-9_'].repeat(1) }

接受除" else"之外的所有字符串,通过说"任何不以else开头的字符串,或以else开头的字符串,至少还有一个字符"。

注意:这让我思考"为什么else如此特别?"我们应该在这里排除所有关键字吗?

如果a.else.b有效,则无法在标识符级别将其排除。然后更准确地说,path无法"else"

如果你说:

rule(:path)        { else_kw.absent? >> (identifier >> (dot >> identifier).repeat) }

这将排除以' else'开头的任何标识符,例如" elsewise.option"

所以.. absent?还需要匹配一些东西来显示你的块已经结束。

rule(:path)        { (else_kw >> dccurly).absent? >> (identifier >> (dot >> identifier).repeat) }

这里的问题是,我们现在正在将路径与一个dccurly结束的想法联系起来,而else并非严格正确(并且不会处理空格)。那么"路径"不适合放这些东西。

如果我们尝试停止匹配rule(:replacement) { docurly >> space? >> (else_kw >> space? >> dccurly).absent? >> path.as(:item) >> space? >> dccurly} 的替换,那会更容易。

else

这会阻止替换匹配elsewise.something,但会允许else.somethingrule(:replacement) { docurly >> space? >> (else_kw >> (space | dccurly | dot)).absent? >> path.as(:item) >> space? >> dccurly}

如果你不想要" else.something"那么你需要这样的东西:

{{1}}

所以"否则" "其他&#34。和"否则}}"都被阻止了。