【问题标题】:How to Read and Convert from Standard Input text data to Structured Data in Ruby?如何在 Ruby 中读取标准输入文本数据并将其转换为结构化数据?
【发布时间】:2012-01-06 00:45:21
【问题描述】:

我想解析标准输入文本,并获取结构化数据容器对象。 我每次都感到困惑,最后我使用全局变量 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

【问题讨论】:

  • 这是怎么回事?您是否愿意编写更容易集成到更大工具中的代码,而不需要每个工具都单独执行?这对我来说似乎很好。
  • 真的需要nil参数来分割吗?
  • 如果您需要帮助格式化您的数据,您需要提供您尝试解析的数据样本。另外,如果你的代码发现一行有四列或更多列,你会怎么做?

标签: ruby stdin


【解决方案1】:

你所拥有的还不错。也许我会做两件事

  • 使用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 很好的代码总结。我喜欢你发现只有 2 和 3 列很重要的事实。
【解决方案2】:

这样的东西怎么样?启用模块化并为输出添加更多结构。 (可能也想将 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-11
    • 1970-01-01
    • 2017-06-25
    • 1970-01-01
    • 2016-12-20
    • 2014-01-28
    相关资源
    最近更新 更多