【问题标题】:Parsing a possibly nested braced item using a grammar使用语法解析可能嵌套的大括号项
【发布时间】:2018-04-17 21:01:13
【问题描述】:

我开始编写 BibTeX 解析器。我想做的第一件事是解析一个支撑项。例如,大括号项目可以是作者字段或标题。字段中可能有嵌套的大括号。以下代码处理嵌套大括号:

use v6;

my $str = q:to/END/;
  author={Belayneh, M. and Geiger, S. and Matth{\"{a}}i, S.K.}, 
  END

$str .= chomp;

grammar ExtractBraced {
    rule TOP {
        'author=' <braced-item> .*
    }
    rule braced-item      { '{' <-[}]>* '}' }
}

ExtractBraced.parse( $str ).say;

输出

「author={Belayneh, M. and Geiger, S. and Matth{\"{a}}i, S.K.},」
 braced-item => 「{Belayneh, M. and Geiger, S. and Matth{\"{a}」

现在,为了使解析器接受嵌套大括号,我想保留当前解析的左大括号数量的计数器,当遇到右大括号时,我们减少计数器。如果计数器达到零,我们假设我们已经解析了完整的项目。

为了遵循这个想法,我尝试拆分 braced-item 正则表达式,以对每个字符执行语法操作。 (下面braced-item-char 正则表达式上的操作方法应该处理大括号计数器):

grammar ExtractBraced {
    rule TOP {
        'author=' <braced-item> .*
    }
    rule braced-item      { '{' <braced-item-char>* '}' }
    rule braced-item-char { <-[}]> }
}

但是,现在解析突然失败了。可能是一个愚蠢的错误,但我不明白为什么它现在会失败?

【问题讨论】:

  • 1.我的,呃,规则是始终使用token,除非我知道我想要ruleregex。使用token braced-item-char ... 取得进展。 2. 我在几秒钟内通过添加use Grammar::Tracer 隔离了问题。你读过my SO answer about debugging grammars吗? 3. 为什么不让正则表达式引擎跟踪递归级别而不是引入手动计数? 4.你见过my OTT answer to a bibtex question吗?
  • @raiph 谢谢!使用token 而不是rule 解决了这个问题。我很好奇如何让正则表达式引擎跟踪递归?我一定会看看你的其他帖子!
  • 请记住,P6 正则表达式对递归非常满意。也许a balanced brackets example 是为了灵感?
  • @raiph 哇,太棒了!我没想过让规则或令牌递归......再次感谢。
  • 不客气。请注意,除了 P6 的正则表达式引擎 (NQP) 之外,其他一些领先的正则表达式引擎也支持递归,包括 P5 的默认引擎和过去十年左右的 the PCRE engine。也就是说,P6/nqp 语法很甜,与可怕的旧 P5 样式正则表达式语法形成鲜明对比,NQP 很高兴生成一个包含数千个递归匹配对象的解析树,而如果你有很多匹配项,PCRE 会耗尽堆栈空间.

标签: grammar raku


【解决方案1】:

在不知道您希望结果数据的外观的情况下,我会将其更改为如下所示:

my $str = 「author={Belayneh, M. and Geiger, S. and Matth{\"{a}}i, S.K.},」;

grammar ExtractBraced {
    token TOP {
        'author='
        $<author> = <.braced-item>
        .*
    }
    token braced-item {
       '{' ~ '}'

           [
           || <- [{}] >+
           || <.before '{'> <.braced-item>
           ]*
    }
}

ExtractBraced.parse( $str ).say;
「author={Belayneh, M. and Geiger, S. and Matth{\"{a}}i, S.K.},」
 author => 「{Belayneh, M. and Geiger, S. and Matth{\"{a}}i, S.K.}」

如果你想要更多的结构它可能看起来更像这样:

my $str = 「author={Belayneh, M. and Geiger, S. and Matth{\"{a}}i, S.K.},」;

grammar ExtractBraced {
    token TOP {
        'author='
        $<author> = <.braced-item>
        .*
    }
    token braced-part {
        || <- [{}] >+
        || <.before '{'> <braced-item>
    }
    token braced-item {
        '{' ~ '}'
            <braced-part>*
    }
}

class Print {
    method TOP ($/){
        make $<author>.made
    }
    method braced-part ($/){
        make $<braced-item>.?made // ~$/
    }
    method braced-item ($/){
        make [~] @<braced-part>».made
    }
}


my $r = ExtractBraced.parse( $str, :actions(Print) );
say $r;
put();
say $r.made;
「author={Belayneh, M. and Geiger, S. and Matth{\"{a}}i, S.K.},」
 author => 「{Belayneh, M. and Geiger, S. and Matth{\"{a}}i, S.K.}」
  braced-part => 「Belayneh, M. and Geiger, S. and Matth」
  braced-part => 「{\"{a}}」
   braced-item => 「{\"{a}}」
    braced-part => 「\"」
    braced-part => 「{a}」
     braced-item => 「{a}」
      braced-part => 「a」
  braced-part => 「i, S.K.」

Belayneh, M. and Geiger, S. and Matth\"ai, S.K.

请注意,&lt;-[{}]&gt;+ 上的 + 是一种优化,&lt;before '{'&gt; 也可以省略,它仍然可以工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-16
    • 1970-01-01
    • 2016-01-17
    • 2014-07-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多