Я не могу получить точное число из файла CSV, если он начинается с нуля в рубине - PullRequest
0 голосов
/ 26 августа 2018

Описания

Чтение файла CSV в рубине.

  1. У меня есть файл CSV с этим содержанием

    longitude,latitude,phone
    13,139.7113134,35.56712836,0311112222
    
  2. Я читаю файл CSV.

  3. Я получаю данные, не ожидаемые по номеру телефона столбца

Код

uploaded_io = params[:rooms][:file]
rooms_table = CSV.table(uploaded_io.tempfile, encoding: "UTF-8")
rooms_table.each_with_index do |row, i|
  p row
end

puts row:

#<CSV::Row longitude:139.7113134 latitude:35.56712836 phone:52728978 >

Я не понимаю, где стоит номер телефона?Я ожидаю, что номер телефона 0311112222 вместо 52728978

Ответы [ 2 ]

0 голосов
/ 28 августа 2018

Причина, по которой это происходит, в том, что для документов , CSV.table:

Ярлык для:

CSV.read( path, { headers:           true,
                  converters:        :numeric,
                  header_converters: :symbol }.merge(options) )

Примечание converters: :numeric, в котором указывается автоматическое (попытка) преобразование числовых полей в числа. Телефонные номера, конечно, на самом деле не цифры, а строки из цифр.

Если вы не хотите каких-либо разговоров, вы можете передать converters: nil в качестве опции CSV.table.

При условии, что вы do хотите, чтобы преобразователь :numeric продолжал работать в других полях, однако вам необходимо определить свой собственный преобразователь. Конвертер - это Proc, который принимает два аргумента: значение поля и (необязательный) объект FieldInfo. Ваш конвертер может выглядеть так:

NUMERIC_EXCEPT_PHONE_CONVERTER = lambda do |value, field_info|
  if field_info.header == :phone
    value
  else
    CSV::Converters[:float].call(
      CSV::Converters[:integer].call(value))
  end
end

Тогда вы бы использовали его, передав его CSV.table в качестве опции converters:, которая переопределит значение по умолчанию converters: :numeric:

rooms_table = CSV.table("data.csv", encoding: "UTF-8", converters: NUMERIC_EXCEPT_PHONE_CONVERTER)
p rooms_table[0]
# => #<CSV::Row longitude:139.7113134 latitude:35.56712836 phone:"0311112222">

Как видите, значение phone теперь является строкой с ведущим 0.

Вы можете увидеть этот код в действии на repl.it: https://repl.it/@jrunning/WellmadeFarflungCron

Помимо

Почему, спросите вы, это так ужасно?

CSV::Converters[:float].call(
  CSV::Converters[:integer].call(value))

Это потому, что модуль CSV определяет CSV :: Converters таким образом:

Converters  = {
  integer:   lambda { |f|
    Integer(f.encode(ConverterEncoding)) rescue f
  },
  float:     lambda { |f|
    Float(f.encode(ConverterEncoding)) rescue f
  },
  numeric:   [:integer, :float],
  # ...
}

Поскольку преобразователь :numeric не указан как лямбда, а является массивом, который указывает, что это действительно просто «цепочка» преобразователей :integer и :float, мы не можем просто сделать CSV::Converters[:numeric].call(value) ; мы должны вызвать два конвертера вручную. (Если кто-то знает что-то, чего мне не хватает, оставьте комментарий.)

0 голосов
/ 28 августа 2018

Вы можете изменить:

rooms_table = CSV.table(uploaded_io.tempfile, encoding: "UTF-8")

на:

rooms_table = CSV.table(uploaded_io.tempfile, encoding: "UTF-8", converters: nil)

, что не будет преобразовывать / разыгрывать ваши поля (вы получите строки).Преобразователь по умолчанию: numeric, который выполняет преобразования, которые вам не нужны.

Возможные преобразователи, с которыми вы можете работать, можно найти здесь:

https://ruby -doc.орг / STDLIB-2.5.1 / libdoc / CSV / RDoc / CSV.html # конвертеры

...