{ "feed": { "id": "urn:uuid:2e8662fc-461f-58a7-9159-c22ca4880eb0", "link": [ { "@attributes": { "href": "http://darrennewton.com/atom.json", "rel": "self" } }, { "@attributes": { "href": "http://darrennewton.com/" } } ], "title" : "Miscellanea", "subtitle" : "Code, design & cultural ephemera from Darren Newton's brain", "updated" : "2016-12-21T15:18:26-05:00", "author": { "name": "Darren Newton" }, "rights" : "Copyright (c) 2016, Darren Newton", "entry": { "id" : "urn:uuid:f52926a1-aa52-5b2c-81ac-73857042eee9", "link" : "http://darrennewton.com/2010/09/05/convert-csv-to-text-with-ruby/", "summary" : "
\nI\u2019m currently working on a large print project. It\u2019s a membership directory for a non-profit organization and I\u2019m laying it out with Adobe InDesign. The client handed me a CSV dump of their member database for the directory. I\u2019ve mentioned more times than I can count how much I dislike repetition (cutting, pasting, rinse, repeat) so I cooked up some Ruby scripts to parse the CSV into various XML and plaintext formats. ", "content" : "
\nI\u2019m currently working on a large print project. It\u2019s a membership directory for a non-profit organization and I\u2019m laying it out with Adobe InDesign. The client handed me a CSV dump of their member database for the directory. I\u2019ve mentioned more times than I can count how much I dislike repetition (cutting, pasting, rinse, repeat) so I cooked up some Ruby scripts to parse the CSV into various XML and plaintext formats.
\n\nTo make life easier I converted the entire CSV file into an array of hashes like so:
\n\n:::ruby\nrequire 'csv'\n\ndef csv_to_array(file_location)\n csv = CSV::parse(File.open(file_location, 'r') {|f| f.read })\n fields = csv.shift\n csv.collect { |record| Hash[*fields.zip(record).flatten ] } \nend\n\ntest = csv_to_array('test.csv')\n
\n\nThis gets the CSV into a nice array loaded with hashes which names each entry with its corresponding field:
\n\n:::ruby\n{\"name\"=>\"Larry\", \"company\"=>\"Google\"}\n{\"name\"=>\"Curly\", \"company\"=>\"Apple\"}\n{\"name\"=>\"Moe\", \"company\"=>\"Microsoft\"}\n
\n\nGetting the CSV into an array of hashes is pretty convenient. I can now rip through the hashes and do whatever formatting I need. For instance, I needed to create a plaintext file that converted each row in the CSV into a Name, Company
format followed by a line break, which could easily be pasted into an InDesign text box:
:::ruby\ndef csv_to_text(file_location)\n out = \"\"\n rows = csv_to_array(file_location) # get our CSV into an array of hashes\n rows.each do |row|\n\n # Use a HEREDOC to get the formatting we want\n\ntmp = <<HERE \n#{row[\"name\"]}, #{row[\"company\"]}\nHERE\n\n out = out + tmp\n end\n\n save_text(file_location, out) # save a text file\n\nend\n
\n\nThis is all pretty simple, but it saves on a lot of cutting and pasting text from fields in Excel or Numbers, the kind of thing I really dislike. You can also do a lot of text transformation during the same process. Many of the addresses in the CSV needed to be made consistent. I wanted common words like Street, Boulevard, Avenue to get transformed into common abbreviations like St., Blvd., and Ave. We need a function:
\n\n:::ruby\ndef process_address(data)\n if data.nil?\n return data\n end\n\n data.squeeze!(\" \") # remove any double spaces\n data.strip! # remove trailing spaces\n data.gsub!(/Res: /, '')\n data.gsub!(/Court/,'Ct.')\n data.gsub!(/Suite/, 'Ste.')\n data.gsub!(/Drive/, 'Dr.')\n data.gsub!(/Road/, 'Rd.')\n data.gsub!(/Street/, 'St.')\n data.gsub!(/Lane/, 'Ln.')\n data.gsub!(/Avenue/, 'Ave.')\n\n data \nend\n
\n\nNow we can pass our rows through process_address
when writing to the text file to get consistent abbreviations. (I could probably optimize that function by dropping the abbreviations into a hash and iterating through them.)
These are pretty simple little scripts, but they help to quickly automate some very tedious tasks. They're also an example of how scripting languages can help you tackle data entry issues when working with your design tools. For this same project I also needed to generate a large XML file that InDesign could parse and use to build the member directory on its own. I'll cover that chunk of code in my next post.
\n", "title" : "Bending CSVs to your will with Ruby", "updated" : "2010-09-05T19:46:00+00:00" } } }