【问题标题】:Parsing text structured as tree with fixed width columns using parslet in ruby使用ruby中的parslet解析结构为具有固定宽度列的树的文本
【发布时间】:2013-02-07 01:11:37
【问题描述】:

我被困住了。几天来一直试图解析这个文本(看底部)。但是有些事情想不通。首先,文本被格式化为具有固定宽度列的树结构,但确切的列宽取决于最宽的字段。

我正在使用 ruby​​,首先我尝试了 Treetop gem 并取得了一些进展,但后来决定尝试 Parslet,所以我现在正在使用它,它似乎应该更容易使用,但很难找到它的详细文档.

目前我单独解析每一行并创建带有解析条目的数组,但这不正确,因为我松散了结构。我需要递归解析它并处理深度。

我非常感谢任何提示、想法和建议。


这是我当前的代码,它可以工作,但所有数据都被展平了。我目前的想法是递归解析当前行的起始位置是否大于以前的行起始位置(即宽度),因此这意味着我们应该进入更深层次。实际上我设法做到了,但后来我无法正常出门,所以我删除了该代码。

require 'pp'
require 'parslet'
require 'parslet/convenience'


class TextParser < Parslet::Parser
    @@width = 5

    root :text

    rule(:text)   { (line >> newline).repeat }

    rule(:line) { left >> ( topline | subline ).as(:entry) }

    rule(:topline) {
        float.as(:number) >> str('%') >> space >> somestring.as(:string1) >> space >> specialstring.as(:string2) >> space >> specialstring.as(:string3)
    }

    rule(:subline) {
        dynamic { |source, context|
            width = context.captures[:width].to_s.length
            width = width-1 if context.captures[:width].to_s[-1] == '|'
            if width > @@width
                # should be recursive
                result = ( specialline | lastline | otherline | empty )
            else
                result = ( specialline | lastline | otherline | empty )
            end
            @@width = width
            result
        }
    }

    rule(:otherline) {
        somestring.as(:string1)
    }

    rule(:specialline) {
        float.as(:number) >> str('%') >> dash >> space? >> specialstring.as(:string1)
    }

    rule(:lastline) {
        float.as(:number) >> str('%') >> dash >> space? >> str('[...]')
    }

    rule(:empty) {
        space?
    }

    rule(:left) {  seperator.capture(:width) >> dash?.capture(:dash) >> space? }

    rule(:somestring) { match['0-9A-Za-z\.\-'].repeat(1) }
    rule(:specialstring) { match['0-9A-Za-z&()*,\.:<>_~'].repeat(1) }

    rule(:space) { match('[ \t]').repeat(1) }
    rule(:space?) { space.maybe }
    rule(:newline) { space? >> match('[\r\n]').repeat(1) }

    rule(:seperator) { space >> (str('|') >> space?).repeat }
    rule(:dash) { space? >> str('-').repeat(1) }
    rule(:dash?) { dash.maybe }

    rule(:float)   { (digits >> str('.') >> digits) }
    rule(:digits)   { match['0-9'].repeat(1) }

end

parser = TextParser.new

file = File.open("text.txt", "rb")
contents = file.read.to_s
file.close

pp parser.parse_with_debug(contents)

文字看起来像这样 (https://gist.github.com/davispuh/4726538)

 1.23%  somestring  specialstring                    specialstring
        |
        --- specialstring
           |          
           |--12.34%-- specialstring
           |          specialstring
           |          |          
           |          |--12.34%-- specialstring
           |          |          specialstring
           |          |          |          
           |          |          |--12.34%-- specialstring
           |          |           --1.12%-- [...]
           |          |          
           |           --2.23%-- specialstring
           |                     |          
           |                     |--12.34%-- specialstring
           |                     |          specialstring
           |                     |          specialstring
           |                     |          |          
           |                     |          |--12.34%-- specialstring
           |                     |          |          specialstring
           |                     |          |          specialstring
           |                     |           --1.23%-- [...]
           |                     |          
           |                      --1.23%-- [...]
           |                                 
            --1.05%-- [...]

 1.23%  somestring  specialstring                    specialstring
 2.34%  somestring  specialstring                    specialstring  
        |
        --- specialstring
            specialstring
            specialstring
           |          
           |--23.34%-- specialstring
           |          specialstring
           |          specialstring
            --34.56%-- [...]

        |
        --- specialstring
            specialstring
           |          
           |--12.34%-- specialstring
           |          |          
           |          |--100.00%-- specialstring
           |          |          specialstring
           |           --0.00%-- [...]
            --23.34%-- [...]

谢谢:)

【问题讨论】:

  • 是什么生成了该文本,它是否有其他输出数据的方式?您显示并尝试解析的输出并不是真正为解析而设计的。相反,它是为了帮助可视化某些东西。这对人眼来说很好,但对于数据重用来说很糟糕。
  • 反对什么?我看不出这个问题有什么不好。
  • 没错,这就是为什么我需要解析它,但遗憾的是我无法获得任何其他输出:(
  • 你还没有说是什么生成了那个文件。另外,它从哪里获取数据?
  • 查看“perf tutorial”,似乎还有其他更易读的方式来输出数据,尤其是“Machine Readable Output”。我没有玩过它,但它似乎是一个更容易的路径。

标签: ruby parsing text abstract-syntax-tree parslet


【解决方案1】:

我想说的是和“铁皮人”一样的话。必须有另一种格式可以生成数据。

如果你想解析这个... Parslet 就像一个 map/reduce 算法。 You're first pass(解析)并不是为了给你最终的输出,只是为了从你的源文档中捕获你需要的所有信息。

将其存储在树中后,您可以对其进行转换以获得所需的输出。

所以...我会编写一个解析器,将每个空格记录为一个节点,并匹配您需要的文本和百分比。我会将空白节点分组到“缩进”节点中。

然后我会使用转换来用节点数替换空白节点来计算缩进。

记住:Parslet 生成一个标准的 ruby​​ 哈希。然后,您可以编写任何您喜欢的代码来理解这棵树。

解析器只是将文本文件转换为您可以操作的数据结构。

只是重申一下。我认为“铁皮人”有正确的答案.. 以机器可读的方式生成数据。

更新:

对于另一种方法,您可以查看:Indentation sensitive parser using Parslet in Ruby?

【讨论】:

    猜你喜欢
    • 2017-04-15
    • 1970-01-01
    • 1970-01-01
    • 2012-06-10
    • 2011-06-22
    • 1970-01-01
    • 1970-01-01
    • 2010-10-25
    • 1970-01-01
    相关资源
    最近更新 更多