Умнее CSV игнорировать пустые строки в CSV - PullRequest
0 голосов
/ 10 января 2020

Я использую Smarter CSV и обнаружил CSV с пустыми строками. Есть ли способ игнорировать это? Smarter CSV принимает пустую строку в качестве заголовка и неправильно обрабатывает файл. Есть ли способ, которым я могу убить comment_regexp?

mail.attachments.each do | attachment |
        filename = attachment.filename
        #filedata = attachment.decoded
        puts filename 
        begin
          tmp = Tempfile.new(filename)
          tmp.write attachment.decoded
          tmp.close
          puts tmp.path
          f = File.open(tmp.path, "r:bom|utf-8")
          options = {
            :comment_regexp => /^#/
          }
          data = SmarterCSV.process(f, options)
          f.close 
          puts data 

Образец файла:

[test.csv[1]

выход

enter image description here

1 Ответ

2 голосов
/ 11 января 2020

Давайте сначала создадим ваш файл.

str = <<~_
#
# Report
#---------------
Date              header1           header2  header3      header4
        20200 jdk;df           4543 $8333              4387       

        20200 jdk              5004 $945876              67

_

fin_name = 'in'
File.write(fin_name, str)
  #=> 223

Для чтения этого файла необходимо решить две проблемы, используя метод SmarterCSV: : процесс . Во-первых, комментарии - строки, начинающиеся с восьмиугольника ('#') - и пустые строки должны быть пропущены. Во-вторых, разделитель полей не является строкой фиксированной длины.

Первая из этих проблем может быть решена путем установки значения параметра ключа process ':comment_regexp в регулярное выражение:

:comment_regexp => /\A#|\A\s*\z/

, которое читается как «соответствует восьмиграннику» в начале строки (\A является якорем начала строки) или (|) соответствует строке, содержащей ноль или более пробельных символов (\s является пробельным символом и \z является концом of-string anchor) ".

К сожалению, SmarterCSV не способен работать с разделителями полей переменной длины. У него есть опция :col_sep, но его значение должно быть строкой, а не регулярным выражением.

Поэтому мы должны предварительно обработать файл перед использованием SmarterCSV, хотя это не сложно. Пока мы находимся, мы можем также удалить знаки доллара и использовать запятые для разделителей полей. 1

fout_name = 'out.csv'

fout = File.new(fout_name, 'w')
File.foreach(fin_name) do |line|
  fout.puts(line.strip.gsub(/\s+\$?/, ',')) unless 
    line.match?(/\A#|\A\s*\z/)
end
fout.close

Давайте посмотрим на полученный файл.

puts File.read(fout_name)

отображает

Date,header1,header2,header3,header4
20200,jdk;df,4543,8333,4387
20200,jdk,5004,945876,67

Вот так должен выглядеть CSV-файл! Теперь мы можем использовать SmarterCSV для этого файла без указания параметров:

SmarterCSV.process(fout_name)
  #=> [{:date=>20200, :header1=>"jdk;df", :header2=>4543,
  #     :header3=>8333, :header4=>4387},
  #    {:date=>20200, :header1=>"jdk", :header2=>5004,
  #     :header3=>945876, :header4=>67}]

1. Я использовал IO :: foreach , чтобы прочитать файл построчно, а затем записать каждую обработанную строку, которая не является ни комментарием, ни пустой строкой, в выходной файл. Если файл не очень большой, мы можем вместо этого gulp поместить его в строку, изменить строку и записать полученную строку в выходной файл: File.write(fout_name, File.read(fin_name).gsub(/^#.*?\n|^[ \t]*\n|^[ \t]+|[ \t]+$|\$/, '').gsub(/[ \t]+/, ',')). Первое регулярное выражение гласит: «сопоставлять строки, начинающиеся с восьмиугольника или строки, содержащие только пробелы и табуляции или пробелы и табуляции в начале строки или пробелы и табуляции в конце строки или знака доллара». Второй gsub просто преобразует несколько знаков табуляции и пробелов в запятую.

File.new (fout_name, 'w') File.foreach (fin_name) do | line | fout.puts (line.strip.gsub (/ \ s + \ $? /, ',')), если только line.match? (/ \ A # | \ A \ s * \ z /) не заканчивается fout.close

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...