如何从标准输入文本数据读取和转换为Ruby中的结构化数据?

时间:2012-01-06 00:45:21

标签: ruby stdin

我想解析stdin文本,并获取结构化数据容器对象。 我每次都很困惑,最后我使用全局变量,ARGF,每个变量和分裂。 我怎么能做得更好?我怎样才能更轻松地阅读和阅读?或者宝石对我有什么帮助?

以下是我丑陋代码的一个案例:

# encoding: utf-8
$DATA = {}
$COUNT = 0

ARGF.each do |line|
  col = line.split(nil).map(&:to_i)
  if col.count == 1
    next
  elsif col.count == 2
    $DATA[$COUNT][:cut_param] << { :cut_order => col[0], :pick_count => col[1] }
  elsif col.count == 3
    $COUNT += 1
    $DATA[$COUNT] = {
      :card_amount  => col[0],
      :cut_count    => col[1],
      :needle_order => col[2],
      :cut_param    => []
    }
  end
end

2 个答案:

答案 0 :(得分:3)

你所得到的并不是太糟糕。也许我会做两件事

  • 使用case语句代替elsif
  • 附加到数组而不是使用带数字键的哈希,并且必须手动增加计数。

代码:

@data = []

ARGF.each do |line|
  col = line.split.map(&:to_i)
  case col.count
  when 3
    @data << {
      :card_amount  => col[0],
      :cut_count    => col[1],
      :needle_order => col[2],
      :cut_param    => []
    }
  when 2
    @data.last[:cut_param] << { :cut_order => col[0], :pick_count => col[1] }
  end
end

答案 1 :(得分:0)

这样的事情怎么样?启用模块化并为输出添加更多结构。 (可能也想将OrderData放在DataParser模块中......)

# encoding: utf-8

class OrderData < Struct.new(:card_amount, :cut_count, :needle_order, :cut_param)
  # Maybe add functionality if needed (existence checking?)
end

module DataParser
  def parse(lines)
    # Die if we get invalid arguments
    if lines.nil? || lines.length == 0 || !(lines.is_a? Array)
      raise ArgumentError, "DataParser::parse Requires a single Array parameter."
    end

    # Collect up our structured output
    output = []

    # Iterate over the input array structuring each result
    lines.each do |line|
      col = line.split.map(&:to_i)
      if col.count == 1
        next
      elsif col.count == 2
        output.last.cut_param << { :cut_order => col[0], :pick_count => col[1] }
      elsif col.count == 3
        output.push(OrderData.new(
          :card_amount  => col[0],
          :cut_count    => col[1],
          :needle_order => col[2],
          :cut_param    => []
        ))
      end
    end
    # Explictly return the output variable instead of the output of the lines
    # array interation.
    return output
  end
end

# If we're run directly, use the command line input for processing
if __FILE__ == $0
  order_data = DataParser::parse(ARGV)
  puts order_data
end