CaptainPlanet
CaptainPlanet

Reputation: 382

Removing carriage returns from CSV columns using converters in Ruby

I'm trying to remove all line break characters (\n and \r) from within column values on an outbound CSV before its sent. The most straightforward way appears to be with a CSV Converter - however, it doesn't seem to be working for me.

csv_options = {}
csv_options[:force_quotes] = true
csv_options[:col_sep] = "|"
CSV::Converters[:remove_newlines] = lambda{|s| 
  begin 
    s.tr("\n","").tr("\r","")
  rescue ArgumentError
    s
  end
}
csv_options[:converters] = [:remove_newlines]
CSV.open(local_file.path, "wb", csv_options) do |csv|
  ...

When I test this, the other aspects of csv_options (the :force_quotes and :col_sep) both work, but line breaks within fields still remain. Does anyone have any suggestions? Note that, for various reasons, I can't remove the linebreaks directly in the strings (or anywhere within the CSV.open block itself), which is why I'm trying to use the converters.

EDIT: Sharpened up the code a bit based on other users' input, but with the same results. Code I'm using now is:

CSV.open(local_file.path, "wb",
          :force_quotes => true,
          :col_sep => "|",
          :converters => lambda { |s| s.tr("\n\r","") }
        ) do |csv|
  ...

Upvotes: 2

Views: 916

Answers (1)

Aldehir
Aldehir

Reputation: 2053

So, the issue is that you want to convert the output to a file and not the input. The :converters option only handles converting input from a CSV file, it doesn't apply the conversions when writing out in CSV format.

If you really want this functionality you can monkey patch it in:

require 'csv'

class CSV
  alias :old_init_separators :init_separators

  def init_separators(options)
    old_init_separators(options)

    if options.delete(:remove_newlines)
      old_quote = @quote
      @quote = lambda do |field|
        old_quote.call(String(field).tr("\r\n", ""))
      end
    end
  end
end

CSV.open('test.csv', 'wb',
         :force_quotes => true,
         :col_sep => '|',
         :remove_newlines => true) do |csv|

  csv << ["A\r\nB", "C\r\nD"]
  csv << ["E\r\nF", "G\r\nH"]

end

Note the addition of the :remove_newlines option.

$ cat test.csv
"AB"|"CD"
"EF"|"GH"

Upvotes: 1

Related Questions