Ruby CSV для чтения многострочных полей
Я экспортировал таблицы и запросы из SQL, где некоторые поля являются многострочными.
Ruby (1.9+) способ чтения CSV выглядит так:
require 'csv'
CSV.foreach("exported_mysql_table.csv", {:headers=>true}) do |row|
puts row
end
Что прекрасно работает, если мои данные такие:
"id","name","email","potato"
1,"Bob","bob@bob.bob","omnomnom"
2,"Charlie","char@char.com","andcheese"
4,"Doug","diggyd@diglet.com","usemeltattack"
(Первая строка - заголовок / атрибуты)
Но если у меня есть:
"id","name","address","email","potato"
1,"Bob","---
- 101 Cottage row
- Lovely Village
- \"\"
","bob@bob.bob","omnomnom"
2,"Charlie","---
- 102 Flame Street
- \"\"
- \"\"
","char@char.com","andcheese"
4,"Doug","---
- 103 Dark Cave
- Next to some geo dude
- So many bats
","diggyd@diglet.com","usemeltattack"
Тогда я получаю ошибку:
.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/csv.rb:1894:in `block (2 levels) in shift': Missing or stray quote in line 2 (CSV::MalformedCSVError)
Похоже, это связано с тем, что конец строки не имеет закрывающей кавычки, так как он занимает несколько строк.
(Я пробовал 'FasterCSV', этот драгоценный камень стал 'csv' с ruby 1.9)
1 ответ
Ваша проблема не в многострочном, а в неправильном формате CSV.
Заменить \"
и конец пробела после конца строки следующим образом:
require 'csv'
ml = %q{"id","name","address","email","potato"
1,"Bob","---
- 101 Cottage row
- Lovely Village
- \"\"
","bob@bob.bob","omnomnom"
2,"Charlie","---
- 102 Flame Street
- \"\"
- \"\"
","char@char.com","andcheese"
4,"Doug","---
- 103 Dark Cave
- Next to some geo dude
- So many bats
","diggyd@diglet.com","usemeltattack"}
ml.gsub!(/\" \n/,"\"\n").gsub!(/\\\"/,"__")
CSV.parse(ml, {:headers=>true}) do |row|
puts row
end
Это дает:
"id","name","address","email","potato"
1,"Bob","---
- 101 Cottage row
- Lovely Village
- ____
","bob@bob.bob","omnomnom"
etc
Если у вас нет контроля над программой, которая доставляет CSV, вы должны открыть файл, прочитать содержимое, выполнить замену и затем проанализировать CSV. я использую __
здесь, но вы можете использовать другие не конфликтующие символы.