0

簡単なグラフを生成する必要があるため、直接使用できない csv ファイルを使用する必要があります。ファイルを「よりクリーンな」ものに操作する必要があり、ルビーでファイルを解析することを学んでいるので、問題が発生し、全体的な戦略が正しいかどうかわかりません....ここでの私の問題は、主に探しているものに関連しています見つかった場所または一致が見つからなかった場所からオフセットされたデータ。基準を満たす行を見つけたら、その 2 行後の情報を読み取り、その一部を操作する必要があります (最後の列から 2 番目の列に何かを移動します)。

元の csv ファイルは次のとおりです。

component
quantity header,design1,design2,design3,Ref,Units
quantity type,#,#,#,ref#,unit value
component
quantity header,design1,design2,design3,Ref,Units
quantity type,#,#,#,ref#,unit value
component
quantity header,design1,design2,design3,Ref,Units
quantity type,#,#,#,ref#,unit value

望ましい出力:

Component Header,Quantity type Header,Units Header,design1 header,design2 header,design3 header,Ref header
component,quantity type,unit value,#,#,#,n/a
component,quantity type,unit value,#,#,#,n/a
component,quantity type,unit value,#,#,#,n/a
component,quantity type,unit value,#,#,#,n/a
component,quantity type,unit value,#,#,#,n/a

現時点での私のルビースクリプト:

require 'csv'
f = File.new("sp.csv")
o = CSV.open('output.csv', 'w')

f.each_line do |l| #iterate through each line
    data = l.split
    if l !~ /,/ #if the line does not contain a comma it is a component
        o << [data,f.gets] #start writing data, f.gets skips next line but need to skip 2 and split the line to manipulate columns
    else
        o << ['comma'] #just me testing that I can find lines with commas
    end
end

f.gets は次の行をスキップし、それを使用して 2 をスキップする方法がドキュメントでは明確ではありません。その後、その行をコンマで分割し、配列 [列] で行データを操作できると思います。このオフセットの問題は別として、私の一般的なアプローチが良い戦略であるかどうかもわかりません

編集

これが実際のファイルからのいくつかの行です....提供された回答を調べて、すべてが機能するかどうかを確認します。私が持っていたアイデアは、ファイル全体を配列に変換してから読み書きするのではなく、行ごとに読み書きすることです。私の考えでは、これらのファイルが大きくなると、行ごとに実行する方がメモリが少なくて済みます。

助けてくれてありがとう、私は答えを調べてあなたに戻ってきます。

DCB
Result Quantity,BL::BL,BL::BL_DCB-noHeat,DC1::DC1,DC2::DC2,noHS::noHS,20mmHS::20mmHS,Reference,Units
Avg Temperature,82.915,69.226,78.35,78.383,86.6,85.763,N/A,Celsius
RCB
Result Quantity,BL::BL,BL::BL_DCB-noHeat,DC1::DC1,DC2::DC2,noHS::noHS,20mmHS::20mmHS,Reference,Units
Avg Temperature,76.557,68.779,74.705,74.739,80.22,79.397,N/A,Celsius
Antenna
Result Quantity,BL::BL,BL::BL_DCB-noHeat,DC1::DC1,DC2::DC2,noHS::noHS,20mmHS::20mmHS,Reference,Units
Avg Temperature,69.988,65.045,69.203,69.238,73.567,72.777,N/A,Celsius
PCBA_fiberTray
Result Quantity,BL::BL,BL::BL_DCB-noHeat,DC1::DC1,DC2::DC2,noHS::noHS,20mmHS::20mmHS,Reference,Units
Avg Temperature,66.651,65.904,66.513,66.551,72.516,70.47,N/A,Celsius

編集2

以下の回答からいくつかの正規表現を使用して、これを解析するための行ごとの戦略を開発しました。完全を期すための回答として投稿します。

解決策を開発する方法を教えてくれてありがとう

4

3 に答える 3

2

3行のグループにスライスするのはどうですか:

File.read("sp.csv").split("\n").each_slice(3) do |slice|
  o << [slice[0], *slice[2].split(',')]
end
于 2013-01-03T02:30:44.017 に答える
1

私が使用しているコードは、すべてが操作されたcsvファイルを作成します...助けてくれた人に感謝します。

require 'csv'

file_in = File.new('sp1.csv')
file_out = CSV.open('output.csv', 'w')

header = []
row = []


file_in.each_line do |line|

  case line
  when /^[^,]+$/ #Find a component (line with no comma)
    comp_header = file_in.gets.split(',') #header is after component and is split into an arry

    if header.empty? #header
      header.push("Component", comp_header[0], comp_header[-1].strip)
      comp_header[1..-3].each do |h|
        header.push(h)
      end
      file_out << header 

    end
    @comp = line.to_s.strip
    next
  when /,/ #when a row had commas
    puts @comp
    vals = line.split(',') #split up into vals array
    row.push(@comp, vals[0], vals[-1].strip) #add quantity and unit to row array
    vals[1..-3].each do |v| #for values (excluding quanity, units, reference info)
      row.push(v) #add values to row array
    end

  end
    file_out << row #write the current row to csv file
    row = [] #reset the row array to move on to the next component set

end
于 2013-01-06T00:25:15.493 に答える
1

「test.csv」というサンプルに基づいて CSV ファイルを作成しました。

このコードから始めます:

data = File.readlines('test.csv').slice_before(/^component/)

列挙子を取得します。列挙子が返すデータを見ると、次のようになります。

pp data.to_a

[["component\n",
  "quantity header,design1,design2,design3,Ref,Units\n",
  "quantity type,#,#,#,ref#,unit value\n"],
["component\n",
  "quantity header,design1,design2,design3,Ref,Units\n",
  "quantity type,#,#,#,ref#,unit value\n"],
["component\n",
  "quantity header,design1,design2,design3,Ref,Units\n",
  "quantity type,#,#,#,ref#,unit value\n"]]

これは、「コンポーネント」行でサブ配列に分割された配列の配列です。値は現実を反映していないと思いますが、より正確なサンプルがなければ... まあ、GIGO .

「コンポーネント」行が実際には繰り返しの「コンポーネント」行の束ではなく、コンマがない場合は、代わりにこれを使用できます。

data = File.readlines('test.csv').slice_before(/\A[^,]+\Z/)

また:

data = File.readlines('test.csv').slice_before(/^[^,]+$/)

結果は、現在のサンプルと同じになります。

より複雑な正規表現が必要な場合は、次のように置き換えることができます。

/^(?:#{ Regexp.union(%w[component1 component2]).source })$/i

%w[]配列内の任意の単語を見つけるパターンを返します。

/^(?:component1|component2)$/i

そこからdata配列をたどって、次のコマンドを使用して不要なヘッダーをすべて消去できます。

data.map{ |a| a[2..-1] }.flatten

次のようなものを返します。

[
  "quantity type,#,#,#,ref#,unit value\n",
  "quantity type,#,#,#,ref#,unit value\n",
  "quantity type,#,#,#,ref#,unit value\n"
]

これを反復して CSV に渡し、必要に応じて配列に解析できます。

data.map{ |a| a[2..-1].map{ |r| CSV.parse(r) }.flatten }

[
  ["quantity type", "#", "#", "#", "ref#", "unit value"],
  ["quantity type", "#", "#", "#", "ref#", "unit value"],
  ["quantity type", "#", "#", "#", "ref#", "unit value"]
]

以上が、CSV データを分割する方法を考えるための背景です。

このコードの使用:

data.flat_map { |ary|
  component = ary[0].strip
  ary[2..-1].map{ |a|
    data = CSV.parse(a).flatten
    [
      component,
      data.shift,
      data.pop,
      *data[0..-2]
    ]
  }
}

戻り値:

[
  ["component", "quantity type", "unit value", "#", "#", "#"],
  ["component", "quantity type", "unit value", "#", "#", "#"],
  ["component", "quantity type", "unit value", "#", "#", "#"]
]

あとは、使用するヘッダーを作成し、返されたデータを CSV に戻して、出力ファイルを生成できるようにするだけです。CSV ドキュメントを使用して、ここからアクセスできるはずです。


編集:

実際のデータに基づいて、マイナーな調整を加えたバージョンのコードとその出力を次に示します。

require 'csv'
require 'pp'

data = File.readlines('test.csv').slice_before(/^[^,]+$/)

pp data.flat_map { |ary|
  component = ary[0].strip
  ary[2..-1].map{ |a|
    record = CSV.parse(a).flatten
    [
      component,
      record.shift,
      record.pop,
      *record[0..-2]
    ]
  }
}

次のようになります。

[["DCB",
  "Avg Temperature",
  "Celsius",
  "82.915",
  "69.226",
  "78.35",
  "78.383",
  "86.6",
  "85.763"],
["RCB",
  "Avg Temperature",
  "Celsius",
  "76.557",
  "68.779",
  "74.705",
  "74.739",
  "80.22",
  "79.397"],
["Antenna",
  "Avg Temperature",
  "Celsius",
  "69.988",
  "65.045",
  "69.203",
  "69.238",
  "73.567",
  "72.777"],
["PCBA_fiberTray",
  "Avg Temperature",
  "Celsius",
  "66.651",
  "65.904",
  "66.513",
  "66.551",
  "72.516",
  "70.47"]]
于 2013-01-03T04:56:49.967 に答える