我必须处理一个不能直接用于生成简单图表的csv文件。我需要将文件操作成“更清洁”的东西并且遇到问题并且不确定我的整体策略是否正确,因为我只是学习用ruby解析文件....我的问题主要与我寻找从我找到或未找到匹配项的位置偏移的数据。在我找到符合条件的行之后,我需要从它后面的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
使用下面答案中的一些正则表达式,我开发了一个逐行策略来解析这个问题。我会发布它作为完整性的答案。
感谢您帮助我,让我了解开发解决方案的方法
答案 0 :(得分:2)
如何将其切成3行组:
File.read("sp.csv").split("\n").each_slice(3) do |slice|
o << [slice[0], *slice[2].split(',')]
end
答案 1 :(得分: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"]]
答案 2 :(得分: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