2012-01-06 47 views
0

我想解析標準輸入文本,並獲取結構化數據容器對象。 我每次都會混淆,最後我會使用全局變量ARGF來分割。 我該如何做得更好?我怎樣才能更簡單易讀?或者什麼寶石幫助我?如何閱讀標準輸入文本數據並將其轉換爲Ruby中的結構化數據?

下面是我的醜陋的代碼一種情況:

# 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 
+1

這有什麼錯嗎?您是否願意編寫更易於集成到更大工具中的代碼,而不需要每個工具都可以自行執行?這對我來說似乎很好。 – sarnold 2012-01-06 00:49:55

+2

你真的需要零參數來拆分嗎? – 2012-01-06 02:59:39

+0

如果您想幫助格式化數據,則需要提供您嘗試解析的數據樣本。另外,如果你的代碼發現有四列或更多列的行,你會做什麼? – 2012-01-06 04:58:43

回答

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 
+0

+1代碼的完美彙總。我喜歡你發現只有'2'和'3'列是重要的。 – 2012-01-06 05:02:54

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 
相關問題