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

2
  • Here is good starting point to understand CSV reading and parsing. Commented Oct 16, 2014 at 10:43
  • 2
    The CSV library has built-in converters. Commented Oct 16, 2014 at 11:29

3 Answers 3

2

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.

Sign up to request clarification or add additional context in comments.

Comments

1

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

2 Comments

You don't have to explicitly close the file when passing a block to File.open.
write, I am remving it
0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.