【问题标题】:matching tag pairs in Treetop grammarTreetop 语法中的匹配标签对
【发布时间】:2010-11-11 02:10:35
【问题描述】:

我不想重复 the Cthulhu answer,但我想使用 Treetop 匹配成对的开始和结束 HTML 标记。使用this grammar,我可以匹配开始标签和结束标签,但现在我想要一个规则将它们绑定在一起。我尝试了以下方法,但使用它会使我的解析器永远运行(无限循环):

rule html_tag_pair
  html_open_tag (!html_close_tag (html_tag_pair / '' / text / newline /
    whitespace))+ html_close_tag <HTMLTagPair>
end

我试图以递归括号示例和负前瞻示例on the Treetop Github page 为基础。我引用的其他规则如下:

rule newline
  [\n\r] {
    def content
      :newline
    end
  }
end

rule tab
  "\t" {
    def content
      :tab
    end
  }
end

rule whitespace
  (newline / tab / [\s]) {
    def content
      :whitespace
    end
  }
end

rule text
  [^<]+ {
    def content
      [:text, text_value]
    end
  }
end

rule html_open_tag
  "<" html_tag_name attribute_list ">" <HTMLOpenTag>
end

rule html_empty_tag
  "<" html_tag_name attribute_list whitespace* "/>" <HTMLEmptyTag>
end

rule html_close_tag
  "</" html_tag_name ">" <HTMLCloseTag>
end

rule html_tag_name
  [A-Za-z0-9]+ {
    def content
      text_value
    end
  }
end

rule attribute_list
  attribute* {
    def content
      elements.inject({}){ |hash, e| hash.merge(e.content) }
    end
  }
end

rule attribute
  whitespace+ html_tag_name "=" quoted_value {
    def content
      {elements[1].content => elements[3].content}
    end
  }
end

rule quoted_value
  ('"' [^"]* '"' / "'" [^']* "'") {
    def content
      elements[1].text_value
    end
  }
end

我知道我需要允许匹配单个开始或结束标记,但如果存在一对 HTML 标记,我希望将它们组合在一起。将它们与我的语法相匹配似乎最干净,但也许有更好的方法?

【问题讨论】:

  • &lt;html_open_tag&gt; (!html_close_tag(etc 之间应该有一个“+”吗?此外(我承认 Treetop 中的前瞻让我感到困惑)似乎负前瞻适用于不匹配的标签(如
    ,而正前瞻则适用于匹配标签。
  • 嗯,好像不应该有+,因为整个规则是递归的,所以里面可能已经有多个打开的标签了,因为里面还有其他的标签对。

标签: ruby regex parsing grammar treetop


【解决方案1】:

这是一个非常简单的语法,它使用语义谓词来匹配结束标记和开始标记。

grammar SimpleXML
  rule document
    (text / tag)*
  end

  rule text
    [^<]+
  end

  rule tag
    "<" [^>]+ ">" (text / tag)* "</" [^>]+ &{|seq| seq[1].text_value == seq[5].text_value } ">"
  end
end

【讨论】:

    【解决方案2】:

    您只能对每个 HTML 标记对使用单独的规则或使用语义谓词来执行此操作。也就是说,通过保存开始标签(在一个 sempred 中),然后仅在它是相同标签时接受(在另一个 sempred 中)一个结束标签。这在 Treetop 中比它应该做的要困难得多,因为没有方便的地方来保存上下文并且你不能查看解析器堆栈,但这是可能的。

    顺便说一句,在解析 MIME 边界(和 Markdown)时也会出现同样的问题。我没有检查过 Mikel 在 ActionMailer 中的实现(可能他为此使用了嵌套的 Mime 解析器),但在 Treetop 中是可能的。

    http://github.com/cjheath/activefacts/blob/master/lib/activefacts/cql/parser.rb 中,我将上下文保存在一个假输入流中——你可以看到它必须支持哪些方法——因为“输入”在所有语法节点上都可用。我在那里使用 sempreds 有不同的原因,但其中一些技术是适用的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-01-08
      • 1970-01-01
      • 1970-01-01
      • 2011-05-02
      • 1970-01-01
      • 2020-05-19
      • 2010-12-14
      • 1970-01-01
      相关资源
      最近更新 更多