Marco Giusti
Marco Giusti

Reputation: 47

Ruby Script for converting CSV to JSON

#!/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

Answers (3)

tomsoft
tomsoft

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

Stefan
Stefan

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

Alireza
Alireza

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

Related Questions