Причина, по которой это происходит, в том, что для документов , 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)
; мы должны вызвать два конвертера вручную. (Если кто-то знает что-то, чего мне не хватает, оставьте комментарий.)