класс CSV
CSV
Данные CSV (comma-separated variables) представляют собой текстовое представление таблицы:
-
Разделитель строк определяет строки таблицы. Обычный разделитель строк — символ новой строки
"\n". -
Разделитель столбцов определяет поля в строке. Обычный разделитель столбцов — запятая
",".
Эта строка CSV с разделителем строк "\n" и разделителем столбцов ",", содержит три строки и два столбца:
"foo,0\nbar,1\nbaz,2\n"
Несмотря на название CSV, в представлении CSV можно использовать разные разделители.
Для получения более подробной информации о таблицах, см. статью Википедии «Таблица (информация)», особенно раздел «Простая таблица»
Класс CSV
Class Класс CSV предоставляет методы для:
-
Разбора данных CSV из объекта String, файла (через его путь) или объекта IO.
-
Генерации данных CSV в объект String.
Чтобы использовать CSV:
require 'csv'
Все примеры здесь предполагают, что это сделано.
Упрощение
Объект CSV имеет десятки методов экземпляров, которые обеспечивают тонкую настройку разбора и генерации данных CSV. Однако для многих задач подойдут более простые подходы.
В этом разделе обобщены статические методы в CSV, которые позволяют выполнять разбор и генерацию без явного создания объектов CSV. Для получения подробностей см. ссылки.
Простой разбор
Методы разбора обычно возвращают один из следующих вариантов:
-
Массив массивов строк:
-
Внешний массив — это вся «таблица».
-
Каждый внутренний массив — это строка.
-
Каждая строка — это поле.
-
-
Объект
CSV::Table. Для получения подробностей см. CSV с заголовками.
Разбор строки
Входные данные для разбора могут быть строкой:
string = "foo,0\nbar,1\nbaz,2\n"
Метод CSV.parse возвращает все данные CSV:
CSV.parse(string) # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
Метод CSV.parse_line возвращает только первую строку:
CSV.parse_line(string) # => ["foo", "0"]
CSV расширяет класс String методом экземпляра String#parse_csv, который также возвращает только первую строку:
string.parse_csv # => ["foo", "0"]
Разбор через путь к файлу
Входные данные для разбора могут быть в файле:
string = "foo,0\nbar,1\nbaz,2\n" path = 't.csv' File.write(path, string)
Метод CSV.read возвращает все данные CSV:
CSV.read(path) # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
Метод CSV.foreach перебирает, передавая каждую строку в заданный блок:
CSV.foreach(path) do |row| p row end
Вывод:
["foo", "0"] ["bar", "1"] ["baz", "2"]
Метод CSV.table возвращает все данные CSV как объект CSV::Table:
CSV.table(path) # => #<CSV::Table mode:col_or_row row_count:3>
Разбор из открытого потока IO
Входные данные для разбора могут находиться в открытом потоке IO:
Метод CSV.read возвращает все данные CSV:
File.open(path) do |file| CSV.read(file) end # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
Так же, как и метод CSV.parse:
File.open(path) do |file| CSV.parse(file) end # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
Метод CSV.parse_line возвращает только первую строку:
File.open(path) do |file| CSV.parse_line(file) end # => ["foo", "0"]
Метод CSV.foreach перебирает, передавая каждую строку в заданный блок:
File.open(path) do |file|
CSV.foreach(file) do |row|
p row
end
end
Вывод:
["foo", "0"] ["bar", "1"] ["baz", "2"]
Метод CSV.table возвращает все данные CSV как объект CSV::Table:
File.open(path) do |file| CSV.table(file) end # => #<CSV::Table mode:col_or_row row_count:3>
Простая генерация
Метод CSV.generate возвращает строку; в этом примере используется метод CSV#<< для добавления строк, которые должны быть сгенерированы:
output_string = CSV.generate do |csv| csv << ['foo', 0] csv << ['bar', 1] csv << ['baz', 2] end output_string # => "foo,0\nbar,1\nbaz,2\n"
Метод CSV.generate_line возвращает строку, содержащую единственную строку, сконструированную из массива:
CSV.generate_line(['foo', '0']) # => "foo,0\n"
CSV расширяет класс Array методом экземпляра Array#to_csv, который преобразует массив в строку:
['foo', '0'].to_csv # => "foo,0\n"
«Фильтрация» CSV
Метод CSV.filter предоставляет фильтр в стиле Unix для данных CSV. Входные данные обрабатываются для формирования выходных данных:
in_string = "foo,0\nbar,1\nbaz,2\n" out_string = '' CSV.filter(in_string, out_string) do |row| row[0] = row[0].upcase row[1] *= 4 end out_string # => "FOO,0000\nBAR,1111\nBAZ,2222\n"
Объекты CSV
Существует три способа создания объекта CSV:
-
Метод
CSV.newвозвращает новый объект CSV. -
Метод
CSV.instanceвозвращает новый или кэшированный объект CSV. -
Метод CSV() также возвращает новый или кэшированный объект CSV.
Методы экземпляра
CSV имеет три группы методов экземпляра:
-
Свои внутренне определенные методы экземпляра.
-
Методы, включенные модулем
Enumerable. -
Методы, делегированные классу
IO. См. ниже.
Делегированные методы
Для удобства объект CSV делегирует многие методы классу IO. (Некоторые из них имеют оберточную «защитную кодовую оболочку» в CSV.) Вы можете вызвать:
-
IO#string
-
IO#truncate
Параметры
Значения параметров по умолчанию:
DEFAULT_OPTIONS = {
# For both parsing and generating.
col_sep: ",",
row_sep: :auto,
quote_char: '"',
# For parsing.
field_size_limit: nil,
converters: nil,
unconverted_fields: nil,
headers: false,
return_headers: false,
header_converters: nil,
skip_blanks: false,
skip_lines: nil,
liberal_parsing: false,
nil_value: nil,
empty_value: "",
strip: false,
# For generating.
write_headers: nil,
quote_empty: true,
force_quotes: false,
write_converters: nil,
write_nil_value: nil,
write_empty_value: "",
}
Параметры для разбора
Параметры для разбора, описанные подробно ниже, включают:
-
row_sep: Указывает разделитель строк; используется для разделения строк. -
col_sep: Указывает разделитель столбцов; используется для разделения полей. -
quote_char: Указывает символ кавычек; используется для кавычек полей. -
field_size_limit: Указывает максимальный размер поля, разрешенный для обработки. -
converters: Указывает преобразователи полей, которые нужно использовать. -
unconverted_fields: Указывает, будут ли доступны необработанные поля. -
headers: Указывает, содержит ли данные заголовки, или указывает сами заголовки. -
return_headers: Указывает, нужно ли возвращать заголовки. -
header_converters: Указывает преобразователи заголовков, которые нужно использовать. -
skip_blanks: Указывает, должны ли игнорироваться пустые строки. -
skip_lines: Указывает, как распознаются строки комментариев. -
strip: Указывает, нужно ли удалять начальные и конечные пробелы из полей. Это должно быть совместимо сcol_sep; если это не так, будет возбуждено исключениеArgumentError. -
liberal_parsing: Указывает, должна ли программа CSV пытаться анализировать несоответствующие данные. -
nil_value: Указывает объект, который нужно подставить для каждого нулевого (без текста) поля. -
empty_value: Указывает объект, который нужно подставить для каждого пустого поля.
Параметр row_sep
Указывает разделитель строк, строку или символ :auto (см. ниже), используемые как для разбора, так и для генерации.
Значение по умолчанию:
CSV::DEFAULT_OPTIONS.fetch(:row_sep) # => :auto
Когда row_sep — это строка, эта строка становится разделителем строк. Строка String будет преобразована в кодировку данных Encoding перед использованием.
Использование "\n":
row_sep = "\n" str = CSV.generate(row_sep: row_sep) do |csv| csv << [:foo, 0] csv << [:bar, 1] csv << [:baz, 2] end str # => "foo,0\nbar,1\nbaz,2\n" ary = CSV.parse(str) ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
Использование | (пайпа):
row_sep = '|' str = CSV.generate(row_sep: row_sep) do |csv| csv << [:foo, 0] csv << [:bar, 1] csv << [:baz, 2] end str # => "foo,0|bar,1|baz,2|" ary = CSV.parse(str, row_sep: row_sep) ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
Использование -- (два дефиса):
row_sep = '--' str = CSV.generate(row_sep: row_sep) do |csv| csv << [:foo, 0] csv << [:bar, 1] csv << [:baz, 2] end str # => "foo,0--bar,1--baz,2--" ary = CSV.parse(str, row_sep: row_sep) ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
Использование '' (пустая строка):
row_sep = '' str = CSV.generate(row_sep: row_sep) do |csv| csv << [:foo, 0] csv << [:bar, 1] csv << [:baz, 2] end str # => "foo,0bar,1baz,2" ary = CSV.parse(str, row_sep: row_sep) ary # => [["foo", "0bar", "1baz", "2"]]
Когда row_sep — это символ :auto (по умолчанию), при генерации используется "\n" в качестве разделителя строк:
str = CSV.generate do |csv| csv << [:foo, 0] csv << [:bar, 1] csv << [:baz, 2] end str # => "foo,0\nbar,1\nbaz,2\n"
При разборе, с другой стороны, происходит автоматическое обнаружение разделителя строк.
Автообнаружение читает данные вперёд, в поисках следующей последовательности \r\n, \n, или \r. Последовательность будет выбрана, даже если она встречается в цитируемом поле, предполагая, что там будут те же самые окончания строк.
Пример:
str = CSV.generate do |csv| csv << [:foo, 0] csv << [:bar, 1] csv << [:baz, 2] end str # => "foo,0\nbar,1\nbaz,2\n" ary = CSV.parse(str) ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
По умолчанию используется значение $INPUT_RECORD_SEPARATOR ($/) если выполняется одно из следующих условий:
-
Ни одна из указанных последовательностей не найдена.
-
Данные
ARGF,STDIN,STDOUT, илиSTDERR. -
Поток доступен только для вывода.
Очевидно, обнаружение занимает немного времени. Set вручную, если скорость важна. Также обратите внимание, что объекты IO на Windows должны открываться в двоичном режиме, если эта функция будет использоваться, так как перевод кодировки строк может вызвать проблемы с восстановлением позиции документа до её состояния до чтения вперёд.
Вызовет исключение, если заданное значение не может быть преобразовано в строку:
row_sep = BasicObject.new # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>) CSV.generate(ary, row_sep: row_sep) # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>) CSV.parse(str, row_sep: row_sep)
Параметр col_sep
Указывает разделитель полей строк, который будет использоваться как для разбора, так и для генерации. Строка будет преобразована в кодировку данных перед использованием.
Значение по умолчанию:
CSV::DEFAULT_OPTIONS.fetch(:col_sep) # => "," (comma)
Использование значения по умолчанию (запятая):
str = CSV.generate do |csv| csv << [:foo, 0] csv << [:bar, 1] csv << [:baz, 2] end str # => "foo,0\nbar,1\nbaz,2\n" ary = CSV.parse(str) ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
Использование : (двоеточие):
col_sep = ':' str = CSV.generate(col_sep: col_sep) do |csv| csv << [:foo, 0] csv << [:bar, 1] csv << [:baz, 2] end str # => "foo:0\nbar:1\nbaz:2\n" ary = CSV.parse(str, col_sep: col_sep) ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
Использование :: (два двоеточия):
col_sep = '::' str = CSV.generate(col_sep: col_sep) do |csv| csv << [:foo, 0] csv << [:bar, 1] csv << [:baz, 2] end str # => "foo::0\nbar::1\nbaz::2\n" ary = CSV.parse(str, col_sep: col_sep) ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
Использование '' (пустая строка):
col_sep = '' str = CSV.generate(col_sep: col_sep) do |csv| csv << [:foo, 0] csv << [:bar, 1] csv << [:baz, 2] end str # => "foo0\nbar1\nbaz2\n"
Вызовет исключение при разборе с пустой строкой:
col_sep = ''
# Raises ArgumentError (:col_sep must be 1 or more characters: "")
CSV.parse("foo0\nbar1\nbaz2\n", col_sep: col_sep)
Вызовет исключение, если заданное значение не может быть преобразовано в строку:
col_sep = BasicObject.new # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>) CSV.generate(line, col_sep: col_sep) # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>) CSV.parse(str, col_sep: col_sep)
Параметр quote_char
Указывает символ (строка длиной 1), используемый для цитирования полей как при разборе, так и при генерации. Эта String будет преобразована в кодировку данных перед использованием.
Значение по умолчанию:
CSV::DEFAULT_OPTIONS.fetch(:quote_char) # => "\"" (double quote)
Это полезно для приложения, которое неправильно использует ' (одинарную кавычку) для цитирования полей вместо правильной " (двойной кавычки).
Использование значения по умолчанию (двойная кавычка):
str = CSV.generate do |csv| csv << ['foo', 0] csv << ["'bar'", 1] csv << ['"baz"', 2] end str # => "foo,0\n'bar',1\n\"\"\"baz\"\"\",2\n" ary = CSV.parse(str) ary # => [["foo", "0"], ["'bar'", "1"], ["\"baz\"", "2"]]
Использование ' (одинарная кавычка):
quote_char = "'" str = CSV.generate(quote_char: quote_char) do |csv| csv << ['foo', 0] csv << ["'bar'", 1] csv << ['"baz"', 2] end str # => "foo,0\n'''bar''',1\n\"baz\",2\n" ary = CSV.parse(str, quote_char: quote_char) ary # => [["foo", "0"], ["'bar'", "1"], ["\"baz\"", "2"]]
Вызовет исключение, если длина строки больше 1:
# Raises ArgumentError (:quote_char has to be nil or a single character String)
CSV.new('', quote_char: 'xx')
Вызовет исключение, если значение не является строкой:
# Raises ArgumentError (:quote_char has to be nil or a single character String)
CSV.new('', quote_char: :foo)
Параметр field_size_limit
Указывает максимальный размер поля типа Integer.
Значение по умолчанию:
CSV::DEFAULT_OPTIONS.fetch(:field_size_limit) # => nil
Это максимальный размер, до которого CSV будет читать вперёд, в поисках закрывающей кавычки для поля. (На самом деле, он читает до первой новой строки после этого размера.) Если кавычка не будет найдена в пределах ограничения, CSV вызовет MalformedCSVError, предполагая, что данные некорректны. Вы можете использовать это ограничение, чтобы предотвратить DoS-атаки на парсер. Однако это ограничение может привести к отказу от разбора корректных данных; поэтому значение по умолчанию составляет nil (без ограничения).
Для примеров в этом разделе:
str = <<~EOT "a","b" " 2345 ","" EOT str # => "\"a\",\"b\"\n\"\n2345\n\",\"\"\n"
Использование значения по умолчанию nil:
ary = CSV.parse(str) ary # => [["a", "b"], ["\n2345\n", ""]]
Использование 50:
field_size_limit = 50 ary = CSV.parse(str, field_size_limit: field_size_limit) ary # => [["a", "b"], ["\n2345\n", ""]]
Вызовет исключение, если поле слишком длинное:
big_str = "123456789\n" * 1024
# Raises CSV::MalformedCSVError (Field size exceeded in line 1.)
CSV.parse('valid,fields,"' + big_str + '"', field_size_limit: 2048)
Параметр converters
Указывает преобразователи, используемые при разборе полей. См. Преобразователи полей
Значение по умолчанию:
CSV::DEFAULT_OPTIONS.fetch(:converters) # => nil
Значение может быть именем преобразователя поля (см. Предопределённые преобразователи):
str = '1,2,3' # Without a converter array = CSV.parse_line(str) array # => ["1", "2", "3"] # With built-in converter :integer array = CSV.parse_line(str, converters: :integer) array # => [1, 2, 3]
Значение может быть списком преобразователей (см. Списки преобразователей):
str = '1,3.14159' # Without converters array = CSV.parse_line(str) array # => ["1", "3.14159"] # With built-in converters array = CSV.parse_line(str, converters: [:integer, :float]) array # => [1, 3.14159]
Значение может быть пользовательским преобразователем Proc (см. Пользовательские преобразователи полей):
str = ' foo , bar , baz '
# Without a converter
array = CSV.parse_line(str)
array # => [" foo ", " bar ", " baz "]
# With a custom converter
array = CSV.parse_line(str, converters: proc {|field| field.strip })
array # => ["foo", "bar", "baz"]
См. также Пользовательские преобразователи полей
Вызовет исключение, если преобразователь не является именем преобразователя или Proc:
str = 'foo,0' # Raises NoMethodError (undefined method `arity' for nil:NilClass) CSV.parse(str, converters: :foo)
Параметр unconverted_fields
Указывает булево значение, определяющее, доступны ли значения полей без преобразования.
Значение по умолчанию:
CSV::DEFAULT_OPTIONS.fetch(:unconverted_fields) # => nil
Значения полей без преобразования — это значения, найденные в исходных данных до любого преобразования, выполненного с помощью параметра converters.
Когда параметр unconverted_fields имеет значение true, каждый возвращаемый ряд (массив или CSV::Row) имеет дополнительный метод unconverted_fields, который возвращает значения полей без преобразования:
str = <<-EOT foo,0 bar,1 baz,2 EOT # Without unconverted_fields csv = CSV.parse(str, converters: :integer) csv # => [["foo", 0], ["bar", 1], ["baz", 2]] csv.first.respond_to?(:unconverted_fields) # => false # With unconverted_fields csv = CSV.parse(str, converters: :integer, unconverted_fields: true) csv # => [["foo", 0], ["bar", 1], ["baz", 2]] csv.first.respond_to?(:unconverted_fields) # => true csv.first.unconverted_fields # => ["foo", "0"]
Параметр headers
Указывает булево значение, символ, массив или строку для определения заголовков столбцов.
Значение по умолчанию:
CSV::DEFAULT_OPTIONS.fetch(:headers) # => false
Без headers:
str = <<-EOT Name,Count foo,0 bar,1 bax,2 EOT csv = CSV.new(str) csv # => #<CSV io_type:StringIO encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\""> csv.headers # => nil csv.shift # => ["Name", "Count"]
Если установлено значение true или символ :first_row, первая строка данных обрабатывается как строка заголовков:
str = <<-EOT Name,Count foo,0 bar,1 bax,2 EOT csv = CSV.new(str, headers: true) csv # => #<CSV io_type:StringIO encoding:UTF-8 lineno:2 col_sep:"," row_sep:"\n" quote_char:"\"" headers:["Name", "Count"]> csv.headers # => ["Name", "Count"] csv.shift # => #<CSV::Row "Name":"bar" "Count":"1">
Если установлено значение массива, элементы массива обрабатываются как заголовки:
str = <<-EOT foo,0 bar,1 bax,2 EOT csv = CSV.new(str, headers: ['Name', 'Count']) csv csv.headers # => ["Name", "Count"] csv.shift # => #<CSV::Row "Name":"bar" "Count":"1">
Если установлено строковое значение str, вызывается метод CSV::parse_line(str, options) с текущим options, а возвращаемый массив обрабатывается как заголовки:
str = <<-EOT foo,0 bar,1 bax,2 EOT csv = CSV.new(str, headers: 'Name,Count') csv csv.headers # => ["Name", "Count"] csv.shift # => #<CSV::Row "Name":"bar" "Count":"1">
Параметр return_headers
Указывает булево значение, определяющее, возвращает ли метод shift строку заголовков или игнорирует её.
Значение по умолчанию:
CSV::DEFAULT_OPTIONS.fetch(:return_headers) # => false
Примеры:
str = <<-EOT Name,Count foo,0 bar,1 bax,2 EOT # Without return_headers first row is str. csv = CSV.new(str, headers: true) csv.shift # => #<CSV::Row "Name":"foo" "Count":"0"> # With return_headers first row is headers. csv = CSV.new(str, headers: true, return_headers: true) csv.shift # => #<CSV::Row "Name":"Name" "Count":"Count">
Параметр header_converters
Указывает преобразователи, используемые при разборе заголовков. См. Преобразователи заголовков
Значение по умолчанию:
CSV::DEFAULT_OPTIONS.fetch(:header_converters) # => nil
Функционально идентично параметру converters, за исключением:
-
Преобразователи применяются только к строке заголовков.
-
Встроенные преобразователи заголовков — это
:downcaseи:symbol.
Этот раздел предполагает предварительное выполнение:
str = <<-EOT Name,Value foo,0 bar,1 baz,2 EOT # With no header converter table = CSV.parse(str, headers: true) table.headers # => ["Name", "Value"]
Значение может быть именем преобразователя заголовков (см. Предопределённые преобразователи):
table = CSV.parse(str, headers: true, header_converters: :downcase) table.headers # => ["name", "value"]
Значение может быть списком преобразователей (см. Списки преобразователей):
header_converters = [:downcase, :symbol] table = CSV.parse(str, headers: true, header_converters: header_converters) table.headers # => [:name, :value]
Значение может быть пользовательским преобразователем Proc (см. Пользовательские преобразователи заголовков):
upcase_converter = proc {|field| field.upcase }
table = CSV.parse(str, headers: true, header_converters: upcase_converter)
table.headers # => ["NAME", "VALUE"]
См. также Пользовательские преобразователи заголовков
Параметр skip_blanks
Указывает булево значение, определяющее, будут ли игнорироваться пустые строки во входных данных; строка, содержащая разделитель столбцов, не считается пустой.
Значение по умолчанию:
CSV::DEFAULT_OPTIONS.fetch(:skip_blanks) # => false
См. также параметр skiplines.
Для примеров в этом разделе:
str = <<-EOT foo,0 bar,1 baz,2 , EOT
Использование значения по умолчанию, false:
ary = CSV.parse(str) ary # => [["foo", "0"], [], ["bar", "1"], ["baz", "2"], [], [nil, nil]]
Использование true:
ary = CSV.parse(str, skip_blanks: true) ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"], [nil, nil]]
Использование истинного значения:
ary = CSV.parse(str, skip_blanks: :foo) ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"], [nil, nil]]
Параметр skip_lines
Указывает объект для идентификации строк комментариев во вводе, которые будут проигнорированы:
-
Если Regexp, игнорирует строки, которые ему соответствуют.
-
Если строка, преобразует её в Regexp, игнорирует строки, которые ему соответствуют.
-
Если
nil, ни одна строка не считается комментарием.
Значение по умолчанию:
CSV::DEFAULT_OPTIONS.fetch(:skip_lines) # => nil
Для примеров в этом разделе:
str = <<-EOT # Comment foo,0 bar,1 baz,2 # Another comment EOT str # => "# Comment\nfoo,0\nbar,1\nbaz,2\n# Another comment\n"
Использование значения по умолчанию, nil:
ary = CSV.parse(str) ary # => [["# Comment"], ["foo", "0"], ["bar", "1"], ["baz", "2"], ["# Another comment"]]
Использование Regexp:
ary = CSV.parse(str, skip_lines: /^#/) ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
Использование строки:
ary = CSV.parse(str, skip_lines: '#') ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
Вызовет исключение, если задан объект, который не является Regexp, строкой или nil:
# Raises ArgumentError (:skip_lines has to respond to #match: 0) CSV.parse(str, skip_lines: 0)
Параметр strip
Указывает булево значение, определяющее, удалять ли пробелы из каждого входного поля.
Значение по умолчанию:
CSV::DEFAULT_OPTIONS.fetch(:strip) # => false
Со значением по умолчанию false:
ary = CSV.parse_line(' a , b ')
ary # => [" a ", " b "]
Со значением true:
ary = CSV.parse_line(' a , b ', strip: true)
ary # => ["a", "b"]
Параметр liberal_parsing
Указывает булево значение, определяющее, будет ли CSV пытаться разобрать ввод, не соответствующий RFC 4180, например, двойные кавычки в нецитируемых полях.
Значение по умолчанию:
CSV::DEFAULT_OPTIONS.fetch(:liberal_parsing) # => false
Для примеров в этом разделе:
str = 'is,this "three, or four",fields'
Без liberal_parsing:
# Raises CSV::MalformedCSVError (Illegal quoting in str 1.) CSV.parse_line(str)
С liberal_parsing:
ary = CSV.parse_line(str, liberal_parsing: true) ary # => ["is", "this \"three", " or four\"", "fields"]
Параметр nil_value
Указывает объект, который должен быть подставлен для каждого пустого (без текста) поля.
Значение по умолчанию:
CSV::DEFAULT_OPTIONS.fetch(:nil_value) # => nil
Со значением по умолчанию, nil:
CSV.parse_line('a,,b,,c') # => ["a", nil, "b", nil, "c"]
С другим объектом:
CSV.parse_line('a,,b,,c', nil_value: 0) # => ["a", 0, "b", 0, "c"]
Параметр empty_value
Указывает объект, который должен быть подставлен для каждого поля, содержащего пустую строку.
Значение по умолчанию:
CSV::DEFAULT_OPTIONS.fetch(:empty_value) # => "" (empty string)
Со значением по умолчанию, "":
CSV.parse_line('a,"",b,"",c') # => ["a", "", "b", "", "c"]
С другим объектом:
CSV.parse_line('a,"",b,"",c', empty_value: 'x') # => ["a", "x", "b", "x", "c"]
Параметры для генерации
Параметры для генерации, описанные подробно ниже, включают:
-
row_sep: Указывает разделитель строк; используется для разграничения строк. -
col_sep: Указывает разделитель столбцов; используется для разграничения полей. -
quote_char: Указывает символ кавычек; используется для кавычек полей. -
write_headers: Указывает, нужно ли записывать заголовки. -
force_quotes: Указывает, нужно ли заключать каждое выходное поле в кавычки. -
quote_empty: Указывает, нужно ли заключать каждое пустое выходное поле в кавычки. -
write_converters: Указывает используемые преобразователи полей для записи. -
write_nil_value: Указывает объект, который нужно заменить в каждом поле со значениемnil. -
write_empty_value: Указывает объект, который нужно заменить в каждом пустом поле.
Параметр row_sep
Указывает разделитель строк, строку или символ :auto (см. ниже), используемый для парсинга и генерации.
Значение по умолчанию:
CSV::DEFAULT_OPTIONS.fetch(:row_sep) # => :auto
Когда row_sep является строкой, эта строка становится разделителем строк. Строка String будет транскодирована в Encoding данных перед использованием.
Использование "\n":
row_sep = "\n" str = CSV.generate(row_sep: row_sep) do |csv| csv << [:foo, 0] csv << [:bar, 1] csv << [:baz, 2] end str # => "foo,0\nbar,1\nbaz,2\n" ary = CSV.parse(str) ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
Использование | (пайп):
row_sep = '|' str = CSV.generate(row_sep: row_sep) do |csv| csv << [:foo, 0] csv << [:bar, 1] csv << [:baz, 2] end str # => "foo,0|bar,1|baz,2|" ary = CSV.parse(str, row_sep: row_sep) ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
Использование -- (два дефиса):
row_sep = '--' str = CSV.generate(row_sep: row_sep) do |csv| csv << [:foo, 0] csv << [:bar, 1] csv << [:baz, 2] end str # => "foo,0--bar,1--baz,2--" ary = CSV.parse(str, row_sep: row_sep) ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
Использование '' (пустая строка):
row_sep = '' str = CSV.generate(row_sep: row_sep) do |csv| csv << [:foo, 0] csv << [:bar, 1] csv << [:baz, 2] end str # => "foo,0bar,1baz,2" ary = CSV.parse(str, row_sep: row_sep) ary # => [["foo", "0bar", "1baz", "2"]]
Когда row_sep является символом :auto (по умолчанию), при генерации используется "\n" в качестве разделителя строк:
str = CSV.generate do |csv| csv << [:foo, 0] csv << [:bar, 1] csv << [:baz, 2] end str # => "foo,0\nbar,1\nbaz,2\n"
С другой стороны, при парсинге происходит автоматическое определение разделителя строк.
Автоматическое определение считывает данные вперед, ища последовательность \r\n, \n или \r. Последовательность будет выбрана даже если она встречается в цитируемом поле, предполагая, что у вас там будут те же самые окончания строк.
Пример:
str = CSV.generate do |csv| csv << [:foo, 0] csv << [:bar, 1] csv << [:baz, 2] end str # => "foo,0\nbar,1\nbaz,2\n" ary = CSV.parse(str) ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
По умолчанию используется $INPUT_RECORD_SEPARATOR ($/) если выполняется одно из следующих условий:
-
Ни одна из этих последовательностей не найдена.
-
Данные являются
ARGF,STDIN,STDOUTилиSTDERR. -
Поток доступен только для вывода.
Очевидно, обнаружение занимает некоторое время. Установите значение вручную с помощью Set, если скорость важна. Также обратите внимание, что объекты IO на Windows должны быть открыты в двоичном режиме, если эта функция будет использоваться, так как преобразование окончания строк может привести к проблемам с возвратом положения документа к исходному состоянию до чтения.
Вызывает исключение, если заданное значение не может быть преобразовано в строку:
row_sep = BasicObject.new # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>) CSV.generate(ary, row_sep: row_sep) # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>) CSV.parse(str, row_sep: row_sep)
Параметр col_sep
Указывает строковый разделитель полей, используемый при парсинге и генерации. Строка будет транскодирована в кодировку данных перед использованием.
Значение по умолчанию:
CSV::DEFAULT_OPTIONS.fetch(:col_sep) # => "," (comma)
Использование значения по умолчанию (запятая):
str = CSV.generate do |csv| csv << [:foo, 0] csv << [:bar, 1] csv << [:baz, 2] end str # => "foo,0\nbar,1\nbaz,2\n" ary = CSV.parse(str) ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
Использование : (двоеточие):
col_sep = ':' str = CSV.generate(col_sep: col_sep) do |csv| csv << [:foo, 0] csv << [:bar, 1] csv << [:baz, 2] end str # => "foo:0\nbar:1\nbaz:2\n" ary = CSV.parse(str, col_sep: col_sep) ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
Использование :: (два двоеточия):
col_sep = '::' str = CSV.generate(col_sep: col_sep) do |csv| csv << [:foo, 0] csv << [:bar, 1] csv << [:baz, 2] end str # => "foo::0\nbar::1\nbaz::2\n" ary = CSV.parse(str, col_sep: col_sep) ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
Использование '' (пустая строка):
col_sep = '' str = CSV.generate(col_sep: col_sep) do |csv| csv << [:foo, 0] csv << [:bar, 1] csv << [:baz, 2] end str # => "foo0\nbar1\nbaz2\n"
Вызывает исключение при парсинге с пустой строкой:
col_sep = ''
# Raises ArgumentError (:col_sep must be 1 or more characters: "")
CSV.parse("foo0\nbar1\nbaz2\n", col_sep: col_sep)
Вызывает исключение, если заданное значение не может быть преобразовано в строку:
col_sep = BasicObject.new # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>) CSV.generate(line, col_sep: col_sep) # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>) CSV.parse(str, col_sep: col_sep)
Параметр quote_char
Указывает символ (строка длиной 1), используемый для цитирования полей при парсинге и генерации. Эта String будет транскодирована в кодировку данных перед использованием.
Значение по умолчанию:
CSV::DEFAULT_OPTIONS.fetch(:quote_char) # => "\"" (double quote)
Это полезно для приложения, которое неправильно использует ' (одинарная кавычка) для цитирования полей вместо правильной " (двойная кавычка).
Использование значения по умолчанию (двойная кавычка):
str = CSV.generate do |csv| csv << ['foo', 0] csv << ["'bar'", 1] csv << ['"baz"', 2] end str # => "foo,0\n'bar',1\n\"\"\"baz\"\"\",2\n" ary = CSV.parse(str) ary # => [["foo", "0"], ["'bar'", "1"], ["\"baz\"", "2"]]
Использование ' (одинарная кавычка):
quote_char = "'" str = CSV.generate(quote_char: quote_char) do |csv| csv << ['foo', 0] csv << ["'bar'", 1] csv << ['"baz"', 2] end str # => "foo,0\n'''bar''',1\n\"baz\",2\n" ary = CSV.parse(str, quote_char: quote_char) ary # => [["foo", "0"], ["'bar'", "1"], ["\"baz\"", "2"]]
Вызывает исключение, если длина строки больше 1:
# Raises ArgumentError (:quote_char has to be nil or a single character String)
CSV.new('', quote_char: 'xx')
Вызывает исключение, если значение не является строкой:
# Raises ArgumentError (:quote_char has to be nil or a single character String)
CSV.new('', quote_char: :foo)
Параметр write_headers
Указывает булево значение, определяющее, включать ли строку заголовков в выходные данные; игнорируется, если заголовки отсутствуют.
Значение по умолчанию:
CSV::DEFAULT_OPTIONS.fetch(:write_headers) # => nil
Без write_headers:
file_path = 't.csv'
CSV.open(file_path,'w',
:headers => ['Name','Value']
) do |csv|
csv << ['foo', '0']
end
CSV.open(file_path) do |csv|
csv.shift
end # => ["foo", "0"]
С write_headers:
CSV.open(file_path,'w',
:write_headers=> true,
:headers => ['Name','Value']
) do |csv|
csv << ['foo', '0']
end
CSV.open(file_path) do |csv|
csv.shift
end # => ["Name", "Value"]
Параметр force_quotes
Указывает булево значение, определяющее, нужно ли заключать каждое выходное поле в двойные кавычки.
Значение по умолчанию:
CSV::DEFAULT_OPTIONS.fetch(:force_quotes) # => false
Для примеров в этом разделе:
ary = ['foo', 0, nil]
Использование значения по умолчанию, false:
str = CSV.generate_line(ary) str # => "foo,0,\n"
Использование true:
str = CSV.generate_line(ary, force_quotes: true) str # => "\"foo\",\"0\",\"\"\n"
Параметр quote_empty
Указывает булево значение, определяющее, нужно ли заключать пустое значение в двойные кавычки.
Значение по умолчанию:
CSV::DEFAULT_OPTIONS.fetch(:quote_empty) # => true
Со значением по умолчанию true:
CSV.generate_line(['"', ""]) # => "\"\"\"\",\"\"\n"
Со значением false:
CSV.generate_line(['"', ""], quote_empty: false) # => "\"\"\"\",\n"
Параметр write_converters
Указывает преобразователи, которые будут использоваться при генерации полей. См. Преобразователи записи
Значение по умолчанию:
CSV::DEFAULT_OPTIONS.fetch(:write_converters) # => nil
Без преобразователя записи:
str = CSV.generate_line(["\na\n", "\tb\t", " c "]) str # => "\"\na\n\",\tb\t, c \n"
С преобразователем записи:
strip_converter = proc {|field| field.strip }
str = CSV.generate_line(["\na\n", "\tb\t", " c "], write_converters: strip_converter)
str # => "a,b,c\n"
С двумя преобразователями записи (вызываемыми в порядке):
upcase_converter = proc {|field| field.upcase }
downcase_converter = proc {|field| field.downcase }
write_converters = [upcase_converter, downcase_converter]
str = CSV.generate_line(['a', 'b', 'c'], write_converters: write_converters)
str # => "a,b,c\n"
См. также Преобразователи записи
Вызывает исключение, если преобразователь возвращает значение, которое не является nil или не может быть преобразовано в строку:
bad_converter = proc {|field| BasicObject.new }
# Raises NoMethodError (undefined method `is_a?' for #<BasicObject:>)
CSV.generate_line(['a', 'b', 'c'], write_converters: bad_converter)#
Параметр write_nil_value
Указывает объект, который будет заменён на каждое поле со значением nil.
Значение по умолчанию:
CSV::DEFAULT_OPTIONS.fetch(:write_nil_value) # => nil
Без параметра:
str = CSV.generate_line(['a', nil, 'c', nil]) str # => "a,,c,\n"
С параметром:
str = CSV.generate_line(['a', nil, 'c', nil], write_nil_value: "x") str # => "a,x,c,x\n"
Параметр write_empty_value
Указывает объект, который будет заменён на каждое поле со значением пустой строки.
Значение по умолчанию:
CSV::DEFAULT_OPTIONS.fetch(:write_empty_value) # => ""
Без параметра:
str = CSV.generate_line(['a', '', 'c', '']) str # => "a,\"\",c,\"\"\n"
С параметром:
str = CSV.generate_line(['a', '', 'c', ''], write_empty_value: "x") str # => "a,x,c,x\n"
CSV с заголовками
CSV позволяет указывать имена столбцов файла CSV, либо они берутся из данных, либо задаются отдельно. Если заголовки заданы, методы чтения возвращают экземпляр CSV::Table, состоящий из CSV::Row.
# Headers are part of data
data = CSV.parse(<<~ROWS, headers: true)
Name,Department,Salary
Bob,Engineering,1000
Jane,Sales,2000
John,Management,5000
ROWS
data.class #=> CSV::Table
data.first #=> #<CSV::Row "Name":"Bob" "Department":"Engineering" "Salary":"1000">
data.first.to_h #=> {"Name"=>"Bob", "Department"=>"Engineering", "Salary"=>"1000"}
# Headers provided by developer
data = CSV.parse('Bob,Engineering,1000', headers: %i[name department salary])
data.first #=> #<CSV::Row name:"Bob" department:"Engineering" salary:"1000">
Преобразователи
По умолчанию каждое значение (поле или заголовок), проанализированное CSV, преобразуется в строку. Вы можете использовать преобразователь полей или преобразователь заголовков для перехвата и изменения анализируемых значений:
Также по умолчанию каждое значение, которое нужно записать при генерации, записывается «как есть». Вы можете использовать преобразователь записи для изменения значений перед записью.
Указание преобразователей
Вы можете указать преобразователи для парсинга или генерации в аргументе options для различных методов CSV:
-
Параметр
convertersдля преобразования анализируемых значений полей. -
Параметр
header_convertersдля преобразования анализируемых значений заголовков. -
Параметр
write_convertersдля преобразования значений, которые будут записаны (сгенерированы).
Существуют три формы указания преобразователей:
-
Процедура преобразования: выполняемый код для преобразования.
-
Имя преобразователя: имя сохраненного преобразователя.
-
Список преобразователей: массив процедур преобразования, имен преобразователей и списков преобразователей.
Процедуры преобразования
Эта процедура преобразования, strip_converter, принимает значение field и возвращает field.strip:
strip_converter = proc {|field| field.strip }
В этом вызове CSV.parse, ключевой аргумент converters: string_converter указывает, что:
-
Процедура
string_converterбудет вызываться для каждого анализируемого поля. -
Возвращаемое значение преобразователя заменит значение
field.
Пример:
string = " foo , 0 \n bar , 1 \n baz , 2 \n" array = CSV.parse(string, converters: strip_converter) array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
Процедура преобразования может принимать второй аргумент, field_info, который содержит данные о поле. Этот измененный strip_converter отображает свои аргументы:
strip_converter = proc do |field, field_info| p [field, field_info] field.strip end string = " foo , 0 \n bar , 1 \n baz , 2 \n" array = CSV.parse(string, converters: strip_converter) array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
Вывод:
[" foo ", #<struct CSV::FieldInfo index=0, line=1, header=nil>] [" 0 ", #<struct CSV::FieldInfo index=1, line=1, header=nil>] [" bar ", #<struct CSV::FieldInfo index=0, line=2, header=nil>] [" 1 ", #<struct CSV::FieldInfo index=1, line=2, header=nil>] [" baz ", #<struct CSV::FieldInfo index=0, line=3, header=nil>] [" 2 ", #<struct CSV::FieldInfo index=1, line=3, header=nil>]
Каждый объект CSV::FieldInfo отображает:
-
Индекс поля, отсчитываемый с 0.
-
Индекс строки, отсчитываемый с 1.
-
Заголовок поля, если он есть.
Сохраненные преобразователи
Преобразователь может получить имя и храниться в структуре, где методы парсинга могут найти его по имени.
Структура хранения преобразователей полей — Hash CSV::Converters. Она содержит несколько встроенных процедур преобразования:
-
:integer: преобразует каждое целое число, встроенное в строку, в целое число. -
:float: преобразует каждое дробное число, встроенное в строку, в число с плавающей точкой. -
:date: преобразует каждую строковую дату в дату. -
:date_time: преобразует каждую строковую дату-время в дату-время.
. Этот пример создает процедуру преобразования, а затем сохраняет ее:
strip_converter = proc {|field| field.strip }
CSV::Converters[:strip] = strip_converter
Затем метод парсинга может сослаться на преобразователь по его имени, :strip:
string = " foo , 0 \n bar , 1 \n baz , 2 \n" array = CSV.parse(string, converters: :strip) array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
Структура хранения преобразователей заголовков — Hash CSV::HeaderConverters, которая работает аналогично. Она также содержит встроенные процедуры преобразования:
-
:downcase: Приводит каждый заголовок к нижнему регистру. -
:symbol: Преобразует каждый заголовок в символ.
Такой структуры хранения для заголовков записи нет.
Для доступа к сохранённым преобразователям в неглавных потоках Ractor, структура хранения должна быть сначала сделана совместной. Поэтому, Ractor.make_shareable(CSV::Converters) и Ractor.make_shareable(CSV::HeaderConverters) должны быть вызваны перед созданием Ractors, использующих преобразователи, хранящиеся в этих структурах. (Поскольку преобразование структур хранения в совместные влечёт за собой их заморозку, любые пользовательские преобразователи, которые будут использоваться, должны быть добавлены первыми.)
Списки преобразователей
Список преобразователей — это массив, который может включать любые комбинации:
-
Процедуры преобразования.
-
Имена сохранённых преобразователей.
-
Вложенные списки преобразователей.
Примеры:
numeric_converters = [:integer, :float] date_converters = [:date, :date_time] [numeric_converters, strip_converter] [strip_converter, date_converters, :float]
Как процедура преобразования, список преобразователей может быть именован и сохранён в CSV::Converters или CSV::HeaderConverters:
CSV::Converters[:custom] = [strip_converter, date_converters, :float] CSV::HeaderConverters[:custom] = [:downcase, :symbol]
Существует два встроенных списка преобразователей:
CSV::Converters[:numeric] # => [:integer, :float] CSV::Converters[:all] # => [:date_time, :numeric]
Преобразователи полей
Без преобразования все проанализированные поля во всех строках становятся строками:
string = "foo,0\nbar,1\nbaz,2\n" ary = CSV.parse(string) ary # => # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
Когда вы указываете преобразователь поля, каждое проанализированное поле передаётся преобразователю; его возвращаемое значение становится сохранённым значением для поля. Преобразователь может, например, преобразовать целое число, вставленное в строку, в истинное целое число. (Фактически, именно это делает встроенный преобразователь полей :integer.)
Существует три способа использования преобразователей полей.
-
Использование опции converters с методом анализа:
ary = CSV.parse(string, converters: :integer) ary # => [0, 1, 2] # => [["foo", 0], ["bar", 1], ["baz", 2]]
-
Использование опции converters с новым экземпляром CSV:
csv = CSV.new(string, converters: :integer) # Field converters in effect: csv.converters # => [:integer] csv.read # => [["foo", 0], ["bar", 1], ["baz", 2]]
-
Использование метода
convertдля добавления преобразователя поля к экземпляру CSV:csv = CSV.new(string) # Add a converter. csv.convert(:integer) csv.converters # => [:integer] csv.read # => [["foo", 0], ["bar", 1], ["baz", 2]]
Установка преобразователя поля не влияет на уже прочитанные строки:
csv = CSV.new(string) csv.shift # => ["foo", "0"] # Add a converter. csv.convert(:integer) csv.converters # => [:integer] csv.read # => [["bar", 1], ["baz", 2]]
Существуют дополнительные встроенные преобразователи, и также поддерживаются пользовательские преобразователи.
Встроенные преобразователи полей
Встроенные преобразователи полей находятся в хэше CSV::Converters:
-
Каждый ключ — это имя преобразователя поля.
-
Каждое значение — это одно из:
-
Процедура преобразования поля.
-
Массив имён преобразователей поля.
-
Вывод:
CSV::Converters.each_pair do |name, value|
if value.kind_of?(Proc)
p [name, value.class]
else
p [name, value]
end
end
Выход:
[:integer, Proc] [:float, Proc] [:numeric, [:integer, :float]] [:date, Proc] [:date_time, Proc] [:all, [:date_time, :numeric]]
Каждый из этих преобразователей транскодирует значения в UTF-8 перед выполнением преобразования. Если значение не может быть транскодировано в UTF-8, преобразование завершится неудачей, а значение останется не преобразованным.
Преобразователь :integer преобразует каждое поле, которое принимает Integer():
data = '0,1,2,x' # Without the converter csv = CSV.parse_line(data) csv # => ["0", "1", "2", "x"] # With the converter csv = CSV.parse_line(data, converters: :integer) csv # => [0, 1, 2, "x"]
Преобразователь :float преобразует каждое поле, которое принимает Float():
data = '1.0,3.14159,x' # Without the converter csv = CSV.parse_line(data) csv # => ["1.0", "3.14159", "x"] # With the converter csv = CSV.parse_line(data, converters: :float) csv # => [1.0, 3.14159, "x"]
Преобразователь :numeric преобразует с использованием как :integer, так и :float.
Преобразователь :date преобразует каждое поле, которое принимает Date::parse:
data = '2001-02-03,x' # Without the converter csv = CSV.parse_line(data) csv # => ["2001-02-03", "x"] # With the converter csv = CSV.parse_line(data, converters: :date) csv # => [#<Date: 2001-02-03 ((2451944j,0s,0n),+0s,2299161j)>, "x"]
Преобразователь :date_time преобразует каждое поле, которое принимает DateTime::parse:
data = '2020-05-07T14:59:00-05:00,x' # Without the converter csv = CSV.parse_line(data) csv # => ["2020-05-07T14:59:00-05:00", "x"] # With the converter csv = CSV.parse_line(data, converters: :date_time) csv # => [#<DateTime: 2020-05-07T14:59:00-05:00 ((2458977j,71940s,0n),-18000s,2299161j)>, "x"]
Преобразователь :numeric преобразует с использованием как :date_time, так и :numeric.
Как показано выше, метод convert добавляет преобразователи к экземпляру CSV, а метод converters возвращает массив действующих преобразователей:
csv = CSV.new('0,1,2')
csv.converters # => []
csv.convert(:integer)
csv.converters # => [:integer]
csv.convert(:date)
csv.converters # => [:integer, :date]
Пользовательские преобразователи полей
Вы можете определить пользовательский преобразователь поля:
strip_converter = proc {|field| field.strip }
string = " foo , 0 \n bar , 1 \n baz , 2 \n"
array = CSV.parse(string, converters: strip_converter)
array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
Вы можете зарегистрировать преобразователь в хэше Converters, что позволяет ссылаться на него по имени:
CSV::Converters[:strip] = strip_converter string = " foo , 0 \n bar , 1 \n baz , 2 \n" array = CSV.parse(string, converters: :strip) array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
Преобразователи заголовков
Преобразователи заголовков работают только с заголовками (а не с другими строками).
Существует три способа использования преобразователей заголовков; эти примеры используют встроенный преобразователь заголовков :dowhcase, который преобразует каждый проанализированный заголовок в нижний регистр.
-
Опция
header_convertersс методом анализа singleton:string = "Name,Count\nFoo,0\n,Bar,1\nBaz,2" tbl = CSV.parse(string, headers: true, header_converters: :downcase) tbl.class # => CSV::Table tbl.headers # => ["name", "count"]
-
Опция
header_convertersс новым экземпляром CSV:csv = CSV.new(string, header_converters: :downcase) # Header converters in effect: csv.header_converters # => [:downcase] tbl = CSV.parse(string, headers: true) tbl.headers # => ["Name", "Count"]
-
Methodheader_convertдобавляет преобразователь заголовков к экземпляру CSV:csv = CSV.new(string) # Add a header converter. csv.header_convert(:downcase) csv.header_converters # => [:downcase] tbl = CSV.parse(string, headers: true) tbl.headers # => ["Name", "Count"]
Встроенные преобразователи заголовков
Встроенные преобразователи заголовков находятся в хэше CSV::HeaderConverters. Ключи там — имена преобразователей:
CSV::HeaderConverters.keys # => [:downcase, :symbol]
Преобразователь :downcase преобразует каждый заголовок, переводя его в нижний регистр:
string = "Name,Count\nFoo,0\n,Bar,1\nBaz,2" tbl = CSV.parse(string, headers: true, header_converters: :downcase) tbl.class # => CSV::Table tbl.headers # => ["name", "count"]
Преобразователь :symbol преобразует каждый заголовок в символ:
string = "Name,Count\nFoo,0\n,Bar,1\nBaz,2" tbl = CSV.parse(string, headers: true, header_converters: :symbol) tbl.headers # => [:name, :count]
Подробности:
-
Удаляет ведущие и хвостовые пробелы.
-
Преобразует заголовок в нижний регистр.
-
Заменяет вложенные пробелы подчёркиваниями.
-
Удаляет небуквенно-цифровые символы.
-
Преобразует строку в символ.
Пользовательские преобразователи заголовков
Вы можете определить пользовательский преобразователь заголовков:
upcase_converter = proc {|header| header.upcase }
string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(string, headers: true, header_converters: upcase_converter)
table # => #<CSV::Table mode:col_or_row row_count:4>
table.headers # => ["NAME", "VALUE"]
Вы можете зарегистрировать преобразователь в хэше HeaderConverters, что позволяет ссылаться на него по имени:
CSV::HeaderConverters[:upcase] = upcase_converter table = CSV.parse(string, headers: true, header_converters: :upcase) table # => #<CSV::Table mode:col_or_row row_count:4> table.headers # => ["NAME", "VALUE"]
Преобразователи записи
При указании преобразователя записи для создания CSV, каждое записываемое поле передаётся преобразователю; его возвращаемое значение становится новым значением для поля. Преобразователь может, например, убрать пробелы из поля.
Без преобразователя записи (все поля без изменений):
output_string = CSV.generate do |csv| csv << [' foo ', 0] csv << [' bar ', 1] csv << [' baz ', 2] end output_string # => " foo ,0\n bar ,1\n baz ,2\n"
Использование опции write_converters с двумя пользовательскими преобразователями записи:
strip_converter = proc {|field| field.respond_to?(:strip) ? field.strip : field }
upcase_converter = proc {|field| field.respond_to?(:upcase) ? field.upcase : field }
write_converters = [strip_converter, upcase_converter]
output_string = CSV.generate(write_converters: write_converters) do |csv|
csv << [' foo ', 0]
csv << [' bar ', 1]
csv << [' baz ', 2]
end
output_string # => "FOO,0\nBAR,1\nBAZ,2\n"
Кодировки символов (M17n или мультиязычность)
Этот новый CSV анализатор понимает m17n. Анализатор работает в кодировке Encoding объекта IO или String, который читается или записывается. Ваши данные никогда не транскодируются (если вы не попросите Ruby их транскодировать), и они буквально будут анализироваться в Encoding, в которой они находятся. Таким образом, CSV вернёт массивы или строки строк в Encoding ваших данных. Это достигается транскодированием самого анализатора в вашу Encoding.
Некоторое транскодирование, конечно, должно произойти, чтобы реализовать поддержку этой многокодировки. Например, :col_sep, :row_sep, и :quote_char должны быть транскодированы, чтобы соответствовать вашим данным. Надеюсь, это сделает весь процесс прозрачным, так как по умолчанию CSV должен просто «волшебно» работать с вашими данными. Однако вы можете установить эти значения вручную в целевой Encoding, чтобы избежать трансляции.
Также важно отметить, что, хотя весь основной анализатор CSV теперь Encoding-независимый, некоторые функции таковыми не являются. Например, встроенные преобразователи будут пытаться транскодировать данные в UTF-8 перед выполнением преобразований. Опять же, вы можете предоставить пользовательские преобразователи, которые понимают ваши кодировки, чтобы избежать этого преобразования. Просто слишком сложно поддерживать родные преобразования во всех кодировках Ruby.
В любом случае, практический аспект этого прост: убедитесь, что объекты IO и String, переданные в CSV, имеют установленную соответствующую Encoding, и всё должно работать. CSV методы, которые позволяют вам открыть объекты IO (CSV::foreach(), CSV::open(), CSV::read() и CSV::readlines()) позволяют вам указать Encoding.
Одно небольшое исключение возникает при создании CSV в String с Encoding, несовместимой с ASCII. Для CSV не существует данных, которые можно было бы использовать для подготовки, и поэтому вам, скорее всего, придётся вручную указать желаемую Encoding в большинстве таких случаев. Тем не менее, при использовании CSV::generate_line() или Array#to_csv() он попытается угадать, используя поля в строке вывода.
Я стараюсь указывать любые другие Encoding проблемы в документации методов по мере их возникновения.
Это было протестировано по возможности со всеми кодировками, не являющимися «пустыми», которые поставляются с Ruby. Однако это новый, смелый код, и в нём могут быть ошибки. Пожалуйста, не стесняйтесь сообщить о любых обнаруженных проблемах.
Константы
- ConverterEncoding
-
Кодировка, используемая всеми преобразователями.
- Converters
-
Хэш, содержащий имена и Procs для встроенных преобразователей полей. См. Встроенные преобразователи полей.
Этот хэш намеренно оставлен незамороженным и может быть расширен пользовательскими преобразователями полей. См. Пользовательские преобразователи полей.
- DEFAULT_OPTIONS
-
Значения по умолчанию для параметров метода.
- DateMatcher
-
A
Regexpиспользуемый для поиска и преобразования некоторых распространенныхDateформатов. - DateTimeMatcher
-
A
Regexpиспользуемый для поиска и преобразования некоторых распространенныхDateTimeформатов. - FieldInfo
-
A
FieldInfoStructсодержит сведения о позиции поля в источнике данных, из которого оно было прочитано.CSVпередаст этуStructнекоторым блокам, которые принимают решения на основе структуры поля. См.CSV.convert_fields()для примера.-
index -
Индекс поля в строке (нумерация с нуля).
-
line -
Строка источника данных, из которой взята данная строка.
-
header -
Заголовок столбца, если он доступен.
-
- HeaderConverters
-
Хэш, содержащий имена и Procs для встроенных преобразователей заголовков. См. Встроенные преобразователи заголовков.
Этот хэш намеренно оставлен незамороженным и может быть расширен пользовательскими преобразователями полей. См. Пользовательские преобразователи заголовков.
- VERSION
-
Версия установленной библиотеки.
Атрибуты
:call-seq:
csv.encoding -> endcoding
Возвращает кодировку, используемую для парсинга и генерации; см. Кодировки символов (M17n или Многоязычность):
CSV.new('').encoding # => #<Encoding:UTF-8>
Методы публичного класса
# File lib/csv.rb, line 1064
def filter(input=nil, output=nil, **options)
# parse options for input, output, or both
in_options, out_options = Hash.new, {row_sep: InputRecordSeparator.value}
options.each do |key, value|
case key.to_s
when /\Ain(?:put)?_(.+)\Z/
in_options[$1.to_sym] = value
when /\Aout(?:put)?_(.+)\Z/
out_options[$1.to_sym] = value
else
in_options[key] = value
out_options[key] = value
end
end
# build input and output wrappers
input = new(input || ARGF, **in_options)
output = new(output || $stdout, **out_options)
# process headers
need_manual_header_output =
(in_options[:headers] and
out_options[:headers] == true and
out_options[:write_headers])
if need_manual_header_output
first_row = input.shift
if first_row
if first_row.is_a?(Row)
headers = first_row.headers
yield headers
output << headers
end
yield first_row
output << first_row
end
end
# read, yield, write
input.each do |row|
yield row
output << row
end
end Считывает CSV-входные данные и записывает CSV-выходные данные.
Для каждой входной строки:
-
Преобразует данные в:
-
Объект
CSV::Row, если используются заголовки. -
Массив массивов в противном случае.
-
-
Вызывает блок с этим объектом.
-
Добавляет возвращаемое значение блока в выходные данные.
Аргументы:
-
Источник CSV:
-
Аргумент
in_string, если задан, должен быть объектом String; он будет помещён в новый объектStringIO, размещённый в начале. -
Аргумент
in_io, если задан, должен быть объектомIO, открытым для чтения; по завершении, объектIOбудет закрыт. -
Если ни
in_stringниin_ioне заданы, входной поток по умолчанию — ARGF.
-
-
CSV-выходные данные:
-
Аргумент
out_string, если задан, должен быть объектом String; он будет помещён в новый объектStringIO, размещённый в начале. -
Аргумент
out_io, если задан, должен быть объектомIO, открытым для записи; по завершении, объектIOбудет закрыт. -
Если ни
out_stringниout_ioне заданы, выходной поток по умолчанию —$stdout.
-
-
Аргумент
optionsдолжен быть ключевыми аргументами.-
Каждое имя аргумента, которое начинается с
in_илиinput_, лишается префикса и рассматривается как опция для разбора входных данных. Опцияinput_row_sepпо умолчанию равна$INPUT_RECORD_SEPARATOR. -
Каждое имя аргумента, которое начинается с
out_илиoutput_лишается префикса и рассматривается как опция для генерации выходных данных. Опцияoutput_row_sepпо умолчанию равна$INPUT_RECORD_SEPARATOR. -
Каждый аргумент, не имеющий указанных выше префиксов, рассматривается как опция для разбора входных данных и генерации выходных данных.
-
Пример:
in_string = "foo,0\nbar,1\nbaz,2\n" out_string = '' CSV.filter(in_string, out_string) do |row| row[0] = row[0].upcase row[1] *= 4 end out_string # => "FOO,0000\nBAR,1111\nBAZ,2222\n"
# File lib/csv.rb, line 1215
def foreach(path, mode="r", **options, &block)
return to_enum(__method__, path, mode, **options) unless block_given?
open(path, mode, **options) do |csv|
csv.each(&block)
end
end Вызывает блок с каждой строкой, считанной из источника path или io.
-
Аргумент
path, если задан, должен быть путём к файлу. -
Аргумент
ioдолжен быть объектомIO, который:-
Открыт для чтения; по завершении, объект
IOбудет закрыт. -
Размещён в начале. Чтобы разместить в конце для добавления, используйте метод
CSV.generate. Для любого другого позиционирования передайте предварительно заданный объект StringIO.
-
-
Аргумент
mode, если задан, должен быть режимом файла. См. Режим открытия. -
Аргументы
modeдолжны быть ключевыми опциями. См. Опции для разбора. -
Этот метод опционально принимает дополнительную опцию
:encoding, которую вы можете использовать для указания кодировкиEncodingданных, считанных изpathилиio. Вы должны предоставить её, если ваши данные не в кодировке, заданнойEncoding::default_external. Разбор будет использовать её для определения способа разбора данных. Вы можете предоставить вторуюEncoding, чтобы данные транскодировались при чтении. Например,encoding: 'UTF-32BE:UTF-8'
прочитает данные
UTF-32BEиз файла, но транскодирует их вUTF-8перед разбором.
Без опции headers
Без опции headers, каждая строка возвращается как объект Array.
Эти примеры предполагают предшествующее выполнение:
string = "foo,0\nbar,1\nbaz,2\n" path = 't.csv' File.write(path, string)
Чтение строк из файла по адресу path:
CSV.foreach(path) {|row| p row }
Вывод:
["foo", "0"] ["bar", "1"] ["baz", "2"]
Чтение строк из объекта IO:
File.open(path) do |file|
CSV.foreach(file) {|row| p row }
end
Вывод:
["foo", "0"] ["bar", "1"] ["baz", "2"]
Возвращает новый Enumerator, если блок не задан:
CSV.foreach(path) # => #<Enumerator: CSV:foreach("t.csv", "r")>
CSV.foreach(File.open(path)) # => #<Enumerator: CSV:foreach(#<File:t.csv>, "r")>
Выводит предупреждение, если кодировка не поддерживается:
CSV.foreach(File.open(path), encoding: 'foo:bar') {|row| }
Вывод:
warning: Unsupported encoding foo ignored warning: Unsupported encoding bar ignored
С опцией headers
С опцией {option headers}, каждая строка возвращается как объект CSV::Row.
Эти примеры предполагают предшествующее выполнение:
string = "Name,Count\nfoo,0\nbar,1\nbaz,2\n" path = 't.csv' File.write(path, string)
Чтение строк из файла по адресу path:
CSV.foreach(path, headers: true) {|row| p row }
Вывод:
#<CSV::Row "Name":"foo" "Count":"0"> #<CSV::Row "Name":"bar" "Count":"1"> #<CSV::Row "Name":"baz" "Count":"2">
Чтение строк из объекта IO:
File.open(path) do |file|
CSV.foreach(file, headers: true) {|row| p row }
end
Вывод:
#<CSV::Row "Name":"foo" "Count":"0"> #<CSV::Row "Name":"bar" "Count":"1"> #<CSV::Row "Name":"baz" "Count":"2">
Выбрасывает исключение, если path является строкой, но не путём к читаемому файлу:
# Raises Errno::ENOENT (No such file or directory @ rb_sysopen - nosuch.csv):
CSV.foreach('nosuch.csv') {|row| }
Выбрасывает исключение, если io является объектом IO, но не открыт для чтения:
io = File.open(path, 'w') {|row| }
# Raises TypeError (no implicit conversion of nil into String):
CSV.foreach(io) {|row| }
Выбрасывает исключение, если mode недействителен:
# Raises ArgumentError (invalid access mode nosuch):
CSV.foreach(path, 'nosuch') {|row| }
# File lib/csv.rb, line 1281
def generate(str=nil, **options)
encoding = options[:encoding]
# add a default empty String, if none was given
if str
str = StringIO.new(str)
str.seek(0, IO::SEEK_END)
str.set_encoding(encoding) if encoding
else
str = +""
str.force_encoding(encoding) if encoding
end
csv = new(str, **options) # wrap
yield csv # yield for appending
csv.string # return final String
end -
Аргумент
csv_string, если задан, должен быть объектом String; по умолчанию — пустая строка. -
Аргументы
options, если заданы, должны быть опциями генерации. См. Опции для генерации.
Создаёт новый объект CSV с помощью CSV.new(csv_string, **options); вызывает блок с объектом CSV, который может быть изменён блоком; возвращает строку, сгенерированную из объекта CSV.
Обратите внимание, что переданная строка модифицируется этим методом. Передайте csv_string.dup, если строка должна быть сохранена.
Этот метод имеет одну дополнительную опцию: :encoding, которая устанавливает базу Encoding для вывода, если не указана кодировка str. CSV нуждается в этом подсказке, если вы планируете выводить данные, несовместимые с ASCII.
Добавить строки:
input_string = "foo,0\nbar,1\nbaz,2\n" output_string = CSV.generate(input_string) do |csv| csv << ['bat', 3] csv << ['bam', 4] end output_string # => "foo,0\nbar,1\nbaz,2\nbat,3\nbam,4\n" input_string # => "foo,0\nbar,1\nbaz,2\nbat,3\nbam,4\n" output_string.equal?(input_string) # => true # Same string, modified
Добавить строки в новую строку, сохранив старую строку:
input_string = "foo,0\nbar,1\nbaz,2\n" output_string = CSV.generate(input_string.dup) do |csv| csv << ['bat', 3] csv << ['bam', 4] end output_string # => "foo,0\nbar,1\nbaz,2\nbat,3\nbam,4\n" input_string # => "foo,0\nbar,1\nbaz,2\n" output_string.equal?(input_string) # => false # Different strings
Создать строки из ничего:
output_string = CSV.generate do |csv| csv << ['foo', 0] csv << ['bar', 1] csv << ['baz', 2] end output_string # => "foo,0\nbar,1\nbaz,2\n"
Выбрасывает исключение, если csv_string не является объектом String:
# Raises TypeError (no implicit conversion of Integer into String) CSV.generate(0)
# File lib/csv.rb, line 1329
def generate_line(row, **options)
options = {row_sep: InputRecordSeparator.value}.merge(options)
str = +""
if options[:encoding]
str.force_encoding(options[:encoding])
else
fallback_encoding = nil
output_encoding = nil
row.each do |field|
next unless field.is_a?(String)
fallback_encoding ||= field.encoding
next if field.ascii_only?
output_encoding = field.encoding
break
end
output_encoding ||= fallback_encoding
if output_encoding
str.force_encoding(output_encoding)
end
end
(new(str, **options) << row).string
end Возвращает строку, созданную путём генерации CSV из ary с использованием указанных options.
Аргумент ary должен быть массивом.
Специальные опции:
-
Опция
:row_sepпо умолчанию равна"\n"> on Ruby 3.0 or later and <tt>$INPUT_RECORD_SEPARATOR($/) в противном случае.:$INPUT_RECORD_SEPARATOR # => "\n"
-
Этот метод принимает дополнительную опцию
:encoding, которая задаёт базуEncodingдля вывода. Этот метод попытается угадать вашуEncodingиз первого не-nilполя вrow, если это возможно, но вам может потребоваться использовать этот параметр как план резервного копирования.
Для других options, см. Опции для генерации.
Возвращает строку, сгенерированную из массива:
CSV.generate_line(['foo', '0']) # => "foo,0\n"
Выбрасывает исключение, если ary не является массивом:
# Raises NoMethodError (undefined method `find' for :foo:Symbol) CSV.generate_line(:foo)
# File lib/csv.rb, line 993
def instance(data = $stdout, **options)
# create a _signature_ for this method call, data object and options
sig = [data.object_id] +
options.values_at(*DEFAULT_OPTIONS.keys.sort_by { |sym| sym.to_s })
# fetch or create the instance for this signature
@@instances ||= Hash.new
instance = (@@instances[sig] ||= new(data, **options))
if block_given?
yield instance # run block, if given, returning result
else
instance # or return the instance
end
end Создаёт или извлекает кэшированные объекты CSV. Для аргументов и опций см. CSV.new.
Этот API не является Ractor-безопасным.
Без блока возвращает объект CSV.
Первый вызов instance создаёт и кэширует объект CSV:
s0 = 's0' csv0 = CSV.instance(s0) csv0.class # => CSV
Последующие вызовы instance с тем же string или io извлекают тот же кэшированный объект:
csv1 = CSV.instance(s0) csv1.class # => CSV csv1.equal?(csv0) # => true # Same CSV object
Последующий вызов instance с другим string или io создаёт и кэширует другой объект CSV.
s1 = 's1' csv2 = CSV.instance(s1) csv2.equal?(csv0) # => false # Different CSV object
Все кэшированные объекты остаются доступными:
csv3 = CSV.instance(s0) csv3.equal?(csv0) # true # Same CSV object csv4 = CSV.instance(s1) csv4.equal?(csv2) # true # Same CSV object
При передаче блока, вызывается блок с созданным или извлечённым объектом CSV; возвращается значение результата блока:
CSV.instance(s0) {|csv| :foo } # => :foo
# File lib/csv.rb, line 1744
def initialize(data,
col_sep: ",",
row_sep: :auto,
quote_char: '"',
field_size_limit: nil,
converters: nil,
unconverted_fields: nil,
headers: false,
return_headers: false,
write_headers: nil,
header_converters: nil,
skip_blanks: false,
force_quotes: false,
skip_lines: nil,
liberal_parsing: false,
internal_encoding: nil,
external_encoding: nil,
encoding: nil,
nil_value: nil,
empty_value: "",
strip: false,
quote_empty: true,
write_converters: nil,
write_nil_value: nil,
write_empty_value: "")
raise ArgumentError.new("Cannot parse nil as CSV") if data.nil?
if data.is_a?(String)
@io = StringIO.new(data)
@io.set_encoding(encoding || data.encoding)
else
@io = data
end
@encoding = determine_encoding(encoding, internal_encoding)
@base_fields_converter_options = {
nil_value: nil_value,
empty_value: empty_value,
}
@write_fields_converter_options = {
nil_value: write_nil_value,
empty_value: write_empty_value,
}
@initial_converters = converters
@initial_header_converters = header_converters
@initial_write_converters = write_converters
@parser_options = {
column_separator: col_sep,
row_separator: row_sep,
quote_character: quote_char,
field_size_limit: field_size_limit,
unconverted_fields: unconverted_fields,
headers: headers,
return_headers: return_headers,
skip_blanks: skip_blanks,
skip_lines: skip_lines,
liberal_parsing: liberal_parsing,
encoding: @encoding,
nil_value: nil_value,
empty_value: empty_value,
strip: strip,
}
@parser = nil
@parser_enumerator = nil
@eof_error = nil
@writer_options = {
encoding: @encoding,
force_encoding: (not encoding.nil?),
force_quotes: force_quotes,
headers: headers,
write_headers: write_headers,
column_separator: col_sep,
row_separator: row_sep,
quote_character: quote_char,
quote_empty: quote_empty,
}
@writer = nil
writer if @writer_options[:write_headers]
end Возвращает новый объект CSV, созданный с помощью string или io и указанными options.
-
Аргумент
stringдолжен быть объектом String; он будет помещён в новый объектStringIO, установленный в начало. -
Аргумент
ioдолжен быть объектомIO, который:-
Открыт для чтения; по возвращении объект
IOбудет закрыт. -
Установлен в начало. Чтобы установить в конец для добавления, используйте метод
CSV.generate. Для других позиций используйте предварительно заданный объект StringIO.
-
-
Аргумент
options: См.:По соображениям производительности, параметры не могут быть переопределены в объекте CSV, поэтому указанные здесь останутся.
Помимо методов экземпляра CSV, несколько методов IO делегированы. См. Делегированные методы.
Создайте объект CSV из объекта String:
csv = CSV.new('foo,0')
csv # => #<CSV io_type:StringIO encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
Создайте объект CSV из объекта File:
File.write('t.csv', 'foo,0')
csv = CSV.new(File.open('t.csv'))
csv # => #<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
Вызывает исключение, если аргумент является nil:
# Raises ArgumentError (Cannot parse nil as CSV): CSV.new(nil)
# File lib/csv.rb, line 1424
def open(filename, mode="r", **options)
# wrap a File opened with the remaining +args+ with no newline
# decorator
file_opts = {universal_newline: false}.merge(options)
options.delete(:invalid)
options.delete(:undef)
options.delete(:replace)
begin
f = File.open(filename, mode, **file_opts)
rescue ArgumentError => e
raise unless /needs binmode/.match?(e.message) and mode == "r"
mode = "rb"
file_opts = {encoding: Encoding.default_external}.merge(file_opts)
retry
end
begin
csv = new(f, **options)
rescue Exception
f.close
raise
end
# handle blocks like Ruby's open(), not like the CSV library
if block_given?
begin
yield csv
ensure
csv.close
end
else
csv
end
end Возможные элементы параметров:
hash form:
:invalid => nil # raise error on invalid byte sequence (default)
:invalid => :replace # replace invalid byte sequence
:undef => :replace # replace undefined conversion
:replace => string # replacement string ("?" or "\uFFFD" if not specified) -
Аргумент
path, если задан, должен быть путём к файлу. -
Аргумент
ioдолжен быть объектомIO, который:-
Открыт для чтения; по возвращении объект
IOбудет закрыт. -
Установлен в начало. Чтобы установить в конец для добавления, используйте метод
CSV.generate. Для других позиций используйте предварительно заданный объект StringIO.
-
-
Аргумент
mode, если задан, должен быть режимом файла. См. Режим открытия. -
Аргументы
**optionsдолжны быть ключевыми параметрами. См. Параметры для генерации. -
Этот метод необязательно принимает дополнительный параметр
:encoding, который можно использовать для указанияEncodingданных, считанных изpathилиio. Необходимо предоставить этот параметр, если данные не в кодировке, указанной вEncoding::default_external. Парсинг будет использовать это для определения способа парсинга данных. Можно указать второйEncoding, чтобы данные были транскодированы при чтении. Например,encoding: 'UTF-32BE:UTF-8'
считает данные
UTF-32BEиз файла, но транскодирует их вUTF-8перед парсингом.
Эти примеры предполагают предыдущее выполнение:
string = "foo,0\nbar,1\nbaz,2\n" path = 't.csv' File.write(path, string)
Без блока возвращает новый объект CSV.
Создайте объект CSV, используя путь к файлу:
csv = CSV.open(path) csv # => #<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
Создайте объект CSV, используя открытый файл:
csv = CSV.open(File.open(path)) csv # => #<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
С блоком, вызывается блок с созданным объектом CSV; возвращается значение результата блока:
Используя путь к файлу:
csv = CSV.open(path) {|csv| p csv}
csv # => #<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
Вывод:
#<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
Используя открытый файл:
csv = CSV.open(File.open(path)) {|csv| p csv}
csv # => #<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
Вывод:
#<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
Вызывает исключение, если аргумент не является объектом String или IO:
# Raises TypeError (no implicit conversion of Symbol into String) CSV.open(:foo)
# File lib/csv.rb, line 1571
def parse(str, **options, &block)
csv = new(str, **options)
return csv.each(&block) if block_given?
# slurp contents, if no block is given
begin
csv.read
ensure
csv.close
end
end Парсит string или io с использованием указанных options.
-
Аргумент
stringдолжен быть объектом String; он будет помещён в новый объектStringIO, установленный в начало. -
Аргумент
ioдолжен быть объектомIO, который:-
Открыт для чтения; по возвращении объект
IOбудет закрыт. -
Установлен в начало. Чтобы установить в конец для добавления, используйте метод
CSV.generate. Для других позиций используйте предварительно заданный объект StringIO.
-
-
Аргумент
options: см. Параметры для парсинга
Без опции headers
Случай без опции {опция headers}.
Эти примеры предполагают предыдущее выполнение:
string = "foo,0\nbar,1\nbaz,2\n" path = 't.csv' File.write(path, string)
Без блока возвращает массив массивов, сформированных из источника.
Парсинг строки:
a_of_a = CSV.parse(string) a_of_a # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
Парсинг открытого файла:
a_of_a = File.open(path) do |file| CSV.parse(file) end a_of_a # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
С блоком, вызывается блок с каждым проанализированным рядом:
Парсинг строки:
CSV.parse(string) {|row| p row }
Вывод:
["foo", "0"] ["bar", "1"] ["baz", "2"]
Парсинг открытого файла:
File.open(path) do |file|
CSV.parse(file) {|row| p row }
end
Вывод:
["foo", "0"] ["bar", "1"] ["baz", "2"]
С опцией headers
Случай с опцией {опция headers}.
Эти примеры предполагают предыдущее выполнение:
string = "Name,Count\nfoo,0\nbar,1\nbaz,2\n" path = 't.csv' File.write(path, string)
Без блока возвращает объект CSV::Table, сформированный из источника.
Парсинг строки:
csv_table = CSV.parse(string, headers: ['Name', 'Count']) csv_table # => #<CSV::Table mode:col_or_row row_count:5>
Парсинг открытого файла:
csv_table = File.open(path) do |file| CSV.parse(file, headers: ['Name', 'Count']) end csv_table # => #<CSV::Table mode:col_or_row row_count:4>
С блоком, вызывается блок с каждым проанализированным рядом, который был сформирован в объект CSV::Row:
Парсинг строки:
CSV.parse(string, headers: ['Name', 'Count']) {|row| p row }
Вывод:
# <CSV::Row "Name":"foo" "Count":"0"> # <CSV::Row "Name":"bar" "Count":"1"> # <CSV::Row "Name":"baz" "Count":"2">
Парсинг открытого файла:
File.open(path) do |file|
CSV.parse(file, headers: ['Name', 'Count']) {|row| p row }
end
Вывод:
# <CSV::Row "Name":"foo" "Count":"0"> # <CSV::Row "Name":"bar" "Count":"1"> # <CSV::Row "Name":"baz" "Count":"2">
Вызывает исключение, если аргумент не является объектом String или IO:
# Raises NoMethodError (undefined method `close' for :foo:Symbol) CSV.parse(:foo)
# File lib/csv.rb, line 1644 def parse_line(line, **options) new(line, **options).each.first end
Возвращает данные, полученные при разборе первой строки из string или io с использованием указанных options.
-
Аргумент
stringдолжен быть объектом String; он будет помещён в новый объектStringIO, позиционированный в начале. -
Аргумент
ioдолжен быть объектомIO, который:-
Открыт для чтения; по возвращении объект
IOбудет закрыт. -
Позиционирован в начале. Для позиционирования в конце, для добавления, используйте метод
CSV.generate. Для любого другого позиционирования, передайте предварительно заданный объект StringIO.
-
-
Аргумент
options: см. Параметры разбора
Без параметра headers
Без параметра headers, возвращает первую строку в виде нового массива.
Эти примеры предполагают предыдущее выполнение:
string = "foo,0\nbar,1\nbaz,2\n" path = 't.csv' File.write(path, string)
Разбор первой строки из объекта String:
CSV.parse_line(string) # => ["foo", "0"]
Разбор первой строки из объекта File:
File.open(path) do |file| CSV.parse_line(file) # => ["foo", "0"] end # => ["foo", "0"]
Возвращает nil если аргумент пустая строка:
CSV.parse_line('') # => nil
С параметром headers
С параметром {параметр headers}, возвращает первую строку в виде объекта CSV::Row.
Эти примеры предполагают предыдущее выполнение:
string = "Name,Count\nfoo,0\nbar,1\nbaz,2\n" path = 't.csv' File.write(path, string)
Разбор первой строки из объекта String:
CSV.parse_line(string, headers: true) # => #<CSV::Row "Name":"foo" "Count":"0">
Разбор первой строки из объекта File:
File.open(path) do |file| CSV.parse_line(file, headers: true) end # => #<CSV::Row "Name":"foo" "Count":"0">
Выбрасывает исключение, если аргумент nil:
# Raises ArgumentError (Cannot parse nil as CSV): CSV.parse_line(nil)
# File lib/csv.rb, line 1668
def read(path, **options)
open(path, **options) { |csv| csv.read }
end Открывает указанный source с указанными options (см. CSV.open), читает источник (см. CSV#read) и возвращает результат, который будет либо массивом массивов, либо таблицей CSV::Table.
Без заголовков:
string = "foo,0\nbar,1\nbaz,2\n" path = 't.csv' File.write(path, string) CSV.read(path) # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
С заголовками:
string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" path = 't.csv' File.write(path, string) CSV.read(path, headers: true) # => #<CSV::Table mode:col_or_row row_count:4>
# File lib/csv.rb, line 1676 def readlines(path, **options) read(path, **options) end
Псевдоним для CSV.read.
# File lib/csv.rb, line 1695
def table(path, **options)
default_options = {
headers: true,
converters: :numeric,
header_converters: :symbol,
}
options = default_options.merge(options)
read(path, **options)
end Вызывает CSV.read с source, options, и определёнными значениями по умолчанию:
-
headers:true -
converters::numeric -
header_converters::symbol
Возвращает объект CSV::Table.
Пример:
string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" path = 't.csv' File.write(path, string) CSV.table(path) # => #<CSV::Table mode:col_or_row row_count:4>
Общедоступные методы экземпляров
# File lib/csv.rb, line 2182 def <<(row) writer << row self end
Добавляет строку в self.
-
Аргумент
rowдолжен быть объектом типа Array или объектомCSV::Row. -
Поток вывода должен быть открыт для записи.
Добавление массивов:
CSV.generate do |csv| csv << ['foo', 0] csv << ['bar', 1] csv << ['baz', 2] end # => "foo,0\nbar,1\nbaz,2\n"
Добавление CSV::Rows:
headers = [] CSV.generate do |csv| csv << CSV::Row.new(headers, ['foo', 0]) csv << CSV::Row.new(headers, ['bar', 1]) csv << CSV::Row.new(headers, ['baz', 2]) end # => "foo,0\nbar,1\nbaz,2\n"
Заголовки в объектах CSV::Row не добавляются:
headers = ['Name', 'Count'] CSV.generate do |csv| csv << CSV::Row.new(headers, ['foo', 0]) csv << CSV::Row.new(headers, ['bar', 1]) csv << CSV::Row.new(headers, ['baz', 2]) end # => "foo,0\nbar,1\nbaz,2\n"
Вызывает исключение, если row не является массивом или CSV::Row:
CSV.generate do |csv| # Raises NoMethodError (undefined method `collect' for :foo:Symbol) csv << :foo end
Вызывает исключение, если поток вывода не открыт для записи:
path = 't.csv'
File.write(path, '')
File.open(path) do |file|
CSV.open(file) do |csv|
# Raises IOError (not opened for writing)
csv << ['foo', 0]
end
end
# File lib/csv.rb, line 2071
def binmode?
if @io.respond_to?(:binmode?)
@io.binmode?
else
false
end
end # File lib/csv.rb, line 1833 def col_sep parser.column_separator end
Возвращает закодированный разделитель столбцов; используется для парсинга и записи; см. {Параметр col_sep}:
CSV.new('').col_sep # => ","
# File lib/csv.rb, line 2253 def convert(name = nil, &converter) parser_fields_converter.add_converter(name, &converter) end
-
Без блока устанавливает преобразователь поля (Proc).
-
С блоком определяет и устанавливает пользовательский преобразователь поля.
-
Возвращает массив установленных преобразователей полей.
-
Аргумент
converter_name, если задан, должен быть именем существующего преобразователя поля.
Без блока устанавливает преобразователь поля:
csv = CSV.new('')
csv.convert(:integer)
csv.convert(:float)
csv.convert(:date)
csv.converters # => [:integer, :float, :date]
Блок, если задан, вызывается для каждого поля:
-
Аргумент
field— значение поля. -
Аргумент
field_info— объектCSV::FieldInfoсодержащий детали о поле.
Приведенные примеры предполагают предыдущее выполнение:
string = "foo,0\nbar,1\nbaz,2\n" path = 't.csv' File.write(path, string)
Пример с блоком:
csv = CSV.open(path)
csv.convert {|field, field_info| p [field, field_info]; field.upcase }
csv.read # => [["FOO", "0"], ["BAR", "1"], ["BAZ", "2"]]
Вывод:
["foo", #<struct CSV::FieldInfo index=0, line=1, header=nil>] ["0", #<struct CSV::FieldInfo index=1, line=1, header=nil>] ["bar", #<struct CSV::FieldInfo index=0, line=2, header=nil>] ["1", #<struct CSV::FieldInfo index=1, line=2, header=nil>] ["baz", #<struct CSV::FieldInfo index=0, line=3, header=nil>] ["2", #<struct CSV::FieldInfo index=1, line=3, header=nil>]
Блок не обязан возвращать объект String:
csv = CSV.open(path)
csv.convert {|field, field_info| field.to_sym }
csv.read # => [[:foo, :"0"], [:bar, :"1"], [:baz, :"2"]]
Если converter_name задан, блок не вызывается:
csv = CSV.open(path)
csv.convert(:integer) {|field, field_info| fail 'Cannot happen' }
csv.read # => [["foo", 0], ["bar", 1], ["baz", 2]]
Вызывает исключение во время парсинга, если converter_name не является именем встроенного преобразователя поля:
csv = CSV.open(path) csv.convert(:nosuch) => [nil] # Raises NoMethodError (undefined method `arity' for nil:NilClass) csv.read
# File lib/csv.rb, line 1892
def converters
parser_fields_converter.map do |converter|
name = Converters.rassoc(converter)
name ? name.first : converter
end
end Возвращает массив, содержащий преобразователи полей; см. Преобразователи полей:
csv = CSV.new('')
csv.converters # => []
csv.convert(:integer)
csv.converters # => [:integer]
csv.convert(proc {|x| x.to_s })
csv.converters
Обратите внимание, что вам нужно вызвать +Ractor.make_shareable(CSV::Converters)+ на главном Ractor для использования этого метода.
# File lib/csv.rb, line 2364 def each(&block) parser_enumerator.each(&block) end
Вызывает блок для каждой последующей строки. Источник данных должен быть открыт для чтения.
Без заголовков:
string = "foo,0\nbar,1\nbaz,2\n" csv = CSV.new(string) csv.each do |row| p row end
Вывод:
["foo", "0"] ["bar", "1"] ["baz", "2"]
С заголовками:
string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" csv = CSV.new(string, headers: true) csv.each do |row| p row end
Вывод:
<CSV::Row "Name":"foo" "Value":"0"> <CSV::Row "Name":"bar" "Value":"1"> <CSV::Row "Name":"baz" "Value":"2">
Вызывает исключение, если источник не открыт для чтения:
string = "foo,0\nbar,1\nbaz,2\n" csv = CSV.new(string) csv.close # Raises IOError (not opened for reading) csv.each do |row| p row end
# File lib/csv.rb, line 2107
def eof?
return false if @eof_error
begin
parser_enumerator.peek
false
rescue MalformedCSVError => error
@eof_error = error
false
rescue StopIteration
true
end
end # File lib/csv.rb, line 1863 def field_size_limit parser.field_size_limit end
Возвращает ограничение размера поля; используется для парсинга; см. {Параметр field_size_limit}:
CSV.new('').field_size_limit # => nil
# File lib/csv.rb, line 2079 def flock(*args) raise NotImplementedError unless @io.respond_to?(:flock) @io.flock(*args) end
# File lib/csv.rb, line 1982 def force_quotes? @writer_options[:force_quotes] end
Возвращает значение, определяющее, нужно ли заключать все выходные поля в кавычки; используется для генерации; см. {Параметр force_quotes}:
CSV.new('').force_quotes? # => false
# File lib/csv.rb, line 2319 def header_convert(name = nil, &converter) header_fields_converter.add_converter(name, &converter) end
Блок не обязан возвращать объект String:
csv = CSV.open(path, headers: true)
csv.header_convert {|header, field_info| header.to_sym }
table = csv.read
table.headers # => [:Name, :Value]
Если converter_name задан, блок не вызывается:
csv = CSV.open(path, headers: true)
csv.header_convert(:downcase) {|header, field_info| fail 'Cannot happen' }
table = csv.read
table.headers # => ["name", "value"]
Вызывает исключение во время парсинга, если converter_name не является именем встроенного преобразователя поля:
csv = CSV.open(path, headers: true) csv.header_convert(:nosuch) # Raises NoMethodError (undefined method `arity' for nil:NilClass) csv.read
# File lib/csv.rb, line 1958
def header_converters
header_fields_converter.map do |converter|
name = HeaderConverters.rassoc(converter)
name ? name.first : converter
end
end Возвращает массив, содержащий преобразователи заголовков; используется для парсинга; см. Преобразователи заголовков:
CSV.new('').header_converters # => []
Обратите внимание, что вам нужно вызвать +Ractor.make_shareable(CSV::HeaderConverters)+ на главном Ractor для использования этого метода.
# File lib/csv.rb, line 2435 def header_row? parser.header_row? end
Возвращает true если следующая считываемая строка — строка заголовков; false в противном случае.
Без заголовков:
string = "foo,0\nbar,1\nbaz,2\n" csv = CSV.new(string) csv.header_row? # => false
С заголовками:
string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" csv = CSV.new(string, headers: true) csv.header_row? # => true csv.shift # => #<CSV::Row "Name":"foo" "Value":"0"> csv.header_row? # => false
Вызывает исключение, если источник не открыт для чтения:
string = "foo,0\nbar,1\nbaz,2\n" csv = CSV.new(string) csv.close # Raises IOError (not opened for reading) csv.header_row?
# File lib/csv.rb, line 1916
def headers
if @writer
@writer.headers
else
parsed_headers = parser.headers
return parsed_headers if parsed_headers
raw_headers = @parser_options[:headers]
raw_headers = nil if raw_headers == false
raw_headers
end
end Возвращает значение, определяющее, используются ли заголовки; используется для парсинга; см. {Параметр headers}:
CSV.new('').headers # => nil
# File lib/csv.rb, line 2494
def inspect
str = ["#<", self.class.to_s, " io_type:"]
# show type of wrapped IO
if @io == $stdout then str << "$stdout"
elsif @io == $stdin then str << "$stdin"
elsif @io == $stderr then str << "$stderr"
else str << @io.class.to_s
end
# show IO.path(), if available
if @io.respond_to?(:path) and (p = @io.path)
str << " io_path:" << p.inspect
end
# show encoding
str << " encoding:" << @encoding.name
# show other attributes
["lineno", "col_sep", "row_sep", "quote_char"].each do |attr_name|
if a = __send__(attr_name)
str << " " << attr_name << ":" << a.inspect
end
end
["skip_blanks", "liberal_parsing"].each do |attr_name|
if a = __send__("#{attr_name}?")
str << " " << attr_name << ":" << a.inspect
end
end
_headers = headers
str << " headers:" << _headers.inspect if _headers
str << ">"
begin
str.join('')
rescue # any encoding error
str.map do |s|
e = Encoding::Converter.asciicompat_encoding(s.encoding)
e ? s.encode(e) : s.force_encoding("ASCII-8BIT")
end.join('')
end
end Возвращает строку, отображающую определённые свойства self:
string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" csv = CSV.new(string, headers: true) s = csv.inspect s # => "#<CSV io_type:StringIO encoding:UTF-8 lineno:0 col_sep:\",\" row_sep:\"\\n\" quote_char:\"\\\"\" headers:true>"
# File lib/csv.rb, line 2084 def ioctl(*args) raise NotImplementedError unless @io.respond_to?(:ioctl) @io.ioctl(*args) end
# File lib/csv.rb, line 1992 def liberal_parsing? parser.liberal_parsing? end
Возвращает значение, определяющее, обрабатывать ли некорректный ввод; используется для разбора; см. {Параметр liberal_parsing}:
CSV.new('').liberal_parsing? # => false
# File lib/csv.rb, line 2057 def line parser.line end
Возвращает самую последнюю прочитанную строку:
string = "foo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)
CSV.open(path) do |csv|
csv.each do |row|
p [csv.lineno, csv.line]
end
end
Вывод:
[1, "foo,0\n"] [2, "bar,1\n"] [3, "baz,2\n"]
# File lib/csv.rb, line 2033
def lineno
if @writer
@writer.lineno
else
parser.lineno
end
end Возвращает количество проанализированных или сгенерированных строк.
Разбор:
string = "foo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)
CSV.open(path) do |csv|
csv.each do |row|
p [csv.lineno, row]
end
end
Вывод:
[1, ["foo", "0"]] [2, ["bar", "1"]] [3, ["baz", "2"]]
Генерация:
CSV.generate do |csv| p csv.lineno; csv << ['foo', 0] p csv.lineno; csv << ['bar', 1] p csv.lineno; csv << ['baz', 2] end
Вывод:
0 1 2
# File lib/csv.rb, line 2089 def path @io.path if @io.respond_to?(:path) end
# File lib/csv.rb, line 1853 def quote_char parser.quote_character end
Возвращает закодированный символ кавычек; используется для разбора и записи; см. {Параметр quote_char}:
CSV.new('').quote_char # => "\""
# File lib/csv.rb, line 2399
def read
rows = to_a
if parser.use_headers?
Table.new(rows, headers: parser.headers)
else
rows
end
end Формирует оставшиеся строки из self в:
-
Объект
CSV::Table, если используются заголовки. -
Массив массивов в противном случае.
Источник данных должен быть открыт для чтения.
Без заголовков:
string = "foo,0\nbar,1\nbaz,2\n" path = 't.csv' File.write(path, string) csv = CSV.open(path) csv.read # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
С заголовками:
string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" path = 't.csv' File.write(path, string) csv = CSV.open(path, headers: true) csv.read # => #<CSV::Table mode:col_or_row row_count:4>
Вызывает исключение, если источник не открыт для чтения:
string = "foo,0\nbar,1\nbaz,2\n" csv = CSV.new(string) csv.close # Raises IOError (not opened for reading) csv.read
# File lib/csv.rb, line 1934 def return_headers? parser.return_headers? end
Возвращает значение, определяющее, должны ли возвращаться заголовки; используется для разбора; см. {Параметр return_headers}:
CSV.new('').return_headers? # => false
# File lib/csv.rb, line 2122 def rewind @parser = nil @parser_enumerator = nil @eof_error = nil @writer.rewind if @writer @io.rewind end
Перематывает базовый объект IO и сбрасывает счётчик строк CSV.
# File lib/csv.rb, line 1843 def row_sep parser.row_separator end
Возвращает закодированный разделитель строк; используется для разбора и записи; см. {Параметр row_sep}:
CSV.new('').row_sep # => "\n"
# File lib/csv.rb, line 2472
def shift
if @eof_error
eof_error, @eof_error = @eof_error, nil
raise eof_error
end
begin
parser_enumerator.next
rescue StopIteration
nil
end
end Возвращает следующую строку данных как:
-
Массив, если заголовки не используются.
-
Объект
CSV::Row, если заголовки используются.
Источник данных должен быть открыт для чтения.
Без заголовков:
string = "foo,0\nbar,1\nbaz,2\n" csv = CSV.new(string) csv.shift # => ["foo", "0"] csv.shift # => ["bar", "1"] csv.shift # => ["baz", "2"] csv.shift # => nil
С заголовками:
string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" csv = CSV.new(string, headers: true) csv.shift # => #<CSV::Row "Name":"foo" "Value":"0"> csv.shift # => #<CSV::Row "Name":"bar" "Value":"1"> csv.shift # => #<CSV::Row "Name":"baz" "Value":"2"> csv.shift # => nil
Вызывает исключение, если источник не открыт для чтения:
string = "foo,0\nbar,1\nbaz,2\n" csv = CSV.new(string) csv.close # Raises IOError (not opened for reading) csv.shift
# File lib/csv.rb, line 1971 def skip_blanks? parser.skip_blanks? end
Возвращает значение, определяющее, игнорировать ли пустые строки; используется для разбора; см. {Параметр skip_blanks}:
CSV.new('').skip_blanks? # => false
# File lib/csv.rb, line 1873 def skip_lines parser.skip_lines end
Возвращает Regexp, используемый для идентификации комментариев; используется для разбора; см. {Параметр skip_lines}:
CSV.new('').skip_lines # => nil
# File lib/csv.rb, line 2093 def stat(*args) raise NotImplementedError unless @io.respond_to?(:stat) @io.stat(*args) end
# File lib/csv.rb, line 2098 def to_i raise NotImplementedError unless @io.respond_to?(:to_i) @io.to_i end
# File lib/csv.rb, line 2103 def to_io @io.respond_to?(:to_io) ? @io.to_io : @io end
# File lib/csv.rb, line 1906 def unconverted_fields? parser.unconverted_fields? end
Возвращает значение, определяющее, должны ли быть доступны необработанные поля; используется для разбора; см. {Параметр unconverted_fields}:
CSV.new('').unconverted_fields? # => nil
# File lib/csv.rb, line 1944 def write_headers? @writer_options[:write_headers] end
Возвращает значение, определяющее, должны ли быть записаны заголовки; используется для генерации; см. {Параметр write_headers}:
CSV.new('').write_headers? # => nil
Закрытые методы экземпляра
# File lib/csv.rb, line 2626
def build_fields_converter(initial_converters, options)
fields_converter = FieldsConverter.new(options)
normalize_converters(initial_converters).each do |name, converter|
fields_converter.add_converter(name, &converter)
end
fields_converter
end # File lib/csv.rb, line 2608
def build_header_fields_converter
specific_options = {
builtin_converters_name: :HeaderConverters,
accept_nil: true,
}
options = @base_fields_converter_options.merge(specific_options)
build_fields_converter(@initial_header_converters, options)
end # File lib/csv.rb, line 2596
def build_parser_fields_converter
specific_options = {
builtin_converters_name: :Converters,
}
options = @base_fields_converter_options.merge(specific_options)
build_fields_converter(@initial_converters, options)
end # File lib/csv.rb, line 2621
def build_writer_fields_converter
build_fields_converter(@initial_write_converters,
@write_fields_converter_options)
end # File lib/csv.rb, line 2571
def convert_fields(fields, headers = false)
if headers
header_fields_converter.convert(fields, nil, 0)
else
parser_fields_converter.convert(fields, @headers, lineno)
end
end Обрабатывает fields с помощью @converters, или @header_converters, если headers передано как true, возвращая преобразованный набор полей. Любой преобразователь, изменяющий поле на что-либо кроме String, прерывает цепочку преобразований для этого поля. Это в первую очередь способ повышения эффективности.
# File lib/csv.rb, line 2534
def determine_encoding(encoding, internal_encoding)
# honor the IO encoding if we can, otherwise default to ASCII-8BIT
io_encoding = raw_encoding
return io_encoding if io_encoding
return Encoding.find(internal_encoding) if internal_encoding
if encoding
encoding, = encoding.split(":", 2) if encoding.is_a?(String)
return Encoding.find(encoding)
end
Encoding.default_internal || Encoding.default_external
end # File lib/csv.rb, line 2604 def header_fields_converter @header_fields_converter ||= build_header_fields_converter end
# File lib/csv.rb, line 2549
def normalize_converters(converters)
converters ||= []
unless converters.is_a?(Array)
converters = [converters]
end
converters.collect do |converter|
case converter
when Proc # custom code block
[nil, converter]
else # by name
[converter, nil]
end
end
end # File lib/csv.rb, line 2634 def parser @parser ||= Parser.new(@io, parser_options) end
# File lib/csv.rb, line 2643 def parser_enumerator @parser_enumerator ||= parser.parse end
# File lib/csv.rb, line 2592 def parser_fields_converter @parser_fields_converter ||= build_parser_fields_converter end
# File lib/csv.rb, line 2638
def parser_options
@parser_options.merge(header_fields_converter: header_fields_converter,
fields_converter: parser_fields_converter)
end # File lib/csv.rb, line 2582
def raw_encoding
if @io.respond_to? :internal_encoding
@io.internal_encoding || @io.external_encoding
elsif @io.respond_to? :encoding
@io.encoding
else
nil
end
end Возвращает кодировку внутреннего объекта IO.
# File lib/csv.rb, line 2647 def writer @writer ||= Writer.new(@io, writer_options) end
# File lib/csv.rb, line 2617 def writer_fields_converter @writer_fields_converter ||= build_writer_fields_converter end
# File lib/csv.rb, line 2651
def writer_options
@writer_options.merge(header_fields_converter: header_fields_converter,
fields_converter: writer_fields_converter)
end
Ruby Core © 1993–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.