Строка разбора Ruby CSV с экранированными кавычками

У меня есть строка в моем CSV файле, у которой есть некоторые скрытые кавычки:

173,"Yukihiro \"The Ruby Guy\" Matsumoto","Japan"

Когда я пытаюсь разобрать его, синтаксический анализатор Ruby CSV:

require 'csv'
CSV.foreach('my.csv', headers: true, header_converters: :symbol) do |row|
  puts row
end

Я получаю эту ошибку:

.../1.9.3-p327/lib/ruby/1.9.1/csv.rb:1914:in `block (2 levels) in shift': Missing or stray quote in line 122 (CSV::MalformedCSVError)

Как я могу обойти эту ошибку?

Ответы

Ответ 1

CSV поддерживает "конвертеры", которые мы обычно можем использовать для массажа содержимого поля, прежде чем он вернется к нашему коду. Например, это можно использовать для strip дополнительных пробелов для всех полей в строке.

К сожалению, преобразователи загораются после того, как строка разделена на поля, и во время этого шага, что CSV злится на встроенные кавычки, поэтому нам нужно пройти между шагами "чтение строки" и "проанализировать строка в полях".

Это мой пример файла CSV:

ID,Name,Country
173,"Yukihiro \"The Ruby Guy\" Matsumoto","Japan"

Сохраняя ваш метод CSV.foreach, это мой примерный код для разбора его без сбоев CSV:

require 'csv'
require 'pp'

header = []
File.foreach('test.csv') do |csv_line|

  row = CSV.parse(csv_line.gsub('\"', '""')).first

  if header.empty?
    header = row.map(&:to_sym)
    next
  end

  row = Hash[header.zip(row)]
  pp row
  puts row[:Name]

end

И получившееся значение хэша и имени:

{:ID=>"173", :Name=>"Yukihiro \"The Ruby Guy\" Matsumoto", :Country=>"Japan"}
Yukihiro "The Ruby Guy" Matsumoto

Я предположил, что вы хотите вернуть хэш, потому что вы указали флаг :headers:

CSV.foreach('my.csv', headers: true, header_converters: :symbol) do |row|

Ответ 2

\" является типичным Unix, тогда как Ruby CSV ожидает ""

Чтобы проанализировать его:

require 'csv'
text = File.read('test.csv').gsub(/\\"/,'""')
CSV.parse(text, headers: true, header_converters: :symbol) do |row|
  puts row
end

Примечание. Если ваш файл CSV очень велик, он использует много ОЗУ для чтения всего файла. Рассмотрим чтение файла по одной строке за раз.

Примечание: если ваш файл CSV может иметь косые черты перед косой чертой, используйте предложение Эндрю Гримма ниже, чтобы помочь:

gsub(/(?<!\\)\\"/,'""')

Ответ 3

Откройте файл в MSExcel и сохраните его как MS-DOS Comma Separated (.csv)