Reputation: 47
#!/usr/bin/env ruby
require 'rubygems'
require 'json'
require 'csv'
def is_int(str)
return !!(str =~ /^[-+]?[1-9]([0-9]*)?$/)
end
lines = CSV.open(ARGV[0],{:col_sep => "\|"}).readlines
keys = lines.delete lines.first
File.open(ARGV[1], "w") do |f|
data = lines.map do |values|
is_int(values) ? values.to_i : values.to_s
Hash[keys.zip(values)]
end
f.puts JSON.pretty_generate(data)
end
I have this Ruby script for parsing a csv file and printing a second file in JSON format.
Im not really good with Ruby, but id like to modify it for
- read the csv file
- for any line (excepts the first that is a header)
- create a file.json where the name of the file is the second field of the line
For example:
the csv file:
ID|NAME|SURNAME|TELEPHONE
01|Jhon|Smith|123456
02|Steve|Brown|654321
the output of file jhon.json:
[
{
"ID": "01",
"NAME": "Jhon",
"SURNAME": "Smith",
"TELEPHONE": "123456",
},
]
Can someone help me?
Upvotes: 1
Views: 1298
Reputation: 4577
You are close to the solution, but let's reformat a little bit and simplify it
lines = CSV.open(ARGV[0],{:col_sep => "\|"}).readlines
# remove first entry of the lines array
keys = lines.shift
lines.each do |values|
# convert the line into a hash and transform string into int
hash=Hash[keys.zip(values.map{|val| is_int(val) ? val.to_i : val}) ]
# Write a file with the hash results
File.open("#{hash['NAME']}.json", "w") do |f|
f.write JSON.pretty_generate [hash]
end
end
Here you will open a new file for each line to be saved
Upvotes: 1
Reputation: 114158
The CSV library can handle most of the processing for you:
require 'csv'
require 'json'
options = { col_sep: '|', converters: :numeric, headers: true }
CSV.foreach(ARGV[0], options) do |row|
filename = "#{row['NAME'].downcase}.json"
File.open(filename, 'w') { |f| f << JSON.pretty_generate(row.to_hash) }
end
Passing converters: :numeric
converts numeric fields to numeric types (Integer
and Float
).
The headers: true
options allows you to access a field by its name (e.g. row['NAME']
) and to convert a row to a hash.
Upvotes: 2
Reputation: 2691
tomsoft's solution looks better, but here is mine anyway:
output = []
lines = CSV.open(ARGV[0],{:col_sep => "\|"}).readlines
headers = lines.shift
lines.each_with_index.map do |line, index|
output << Hash[*line.each_with_index.map {|col, index| [headers[index],is_int(col) ? col.to_i : col]}.flatten]
end
File.open(ARGV[1], "w") do |f|
f << output
end
Upvotes: 0