Spec-Zone.ru › Ruby 3.3

класс CSV

Родитель:
Объект
Включенные модули:
Enumerable

CSV

CSV

Данные CSV (значения, разделённые запятыми) представляют собой текстовое представление таблицы:

  • Разделитель строк определяет строки таблицы. Общим разделителем строк является символ новой строки "\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#binmode

  • binmode?

  • IO#close

  • IO#close_read

  • IO#close_write

  • IO#closed?

  • eof

  • eof?

  • IO#external_encoding

  • IO#fcntl

  • IO#fileno

  • flock

  • IO#flush

  • IO#fsync

  • IO#internal_encoding

  • ioctl

  • IO#isatty

  • path

  • IO#pid

  • IO#pos

  • IO#pos=

  • IO#reopen

  • rewind

  • IO#seek

  • stat

  • IO#string

  • IO#sync

  • IO#sync=

  • IO#tell

  • to_i

  • to_io

  • IO#truncate

  • IO#tty?

Параметры

Значения параметров по умолчанию:

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: Указывает максимальный размер поля + 1, разрешённый. Устарело с версии 3.2.3. Используйте max_field_size вместо.

  • max_field_size: Указывает максимальный размер поля.

  • 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"]]

Использование | (pipe):

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 ($/) используется, если выполняется одно из следующих условий:

  • Ни одна из этих последовательностей не найдена.

  • Data является ARGF, STDIN, STDOUT, или STDERR.

  • Поток доступен только для вывода.

Очевидно, что обнаружение занимает некоторое время. Set вручную, если скорость важна. Также обратите внимание, что объекты IO на Windows должны быть открыты в двоичном режиме, если эта функция будет использоваться, так как перевод окончания строки может вызвать проблемы с переустановкой позиции документа к положению до считывания вперёд.

Параметр 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)
Параметр 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

Устанавливает целочисленное ограничение размера поля.

Значение по умолчанию:

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"]

Используйте подпараметр backslash_quote для парсинга значений, в которых символ обратного слэша используется для экранирования символа двойной кавычки. Это заставит парсер рассматривать \" как "".

Для следующих двух примеров:

str = 'Show,"Harry \"Handcuff\" Houdini, the one and only","Tampa Theater"'

Со значением liberal_parsing, но без подпараметра backslash_quote:

# Incorrect interpretation of backslash; incorrectly interprets the quoted comma as a field separator.
ary = CSV.parse_line(str, liberal_parsing: true)
ary # => ["Show", "\"Harry \\\"Handcuff\\\" Houdini", " the one and only\"", "Tampa Theater"]
puts ary[1] # => "Harry \"Handcuff\" Houdini

Со значением liberal_parsing и его подпараметром backslash_quote:

ary = CSV.parse_line(str, liberal_parsing: { backslash_quote: true })
ary # => ["Show", "Harry \"Handcuff\" Houdini, the one and only", "Tampa Theater"]
puts ary[1] # => Harry "Handcuff" Houdini, the one and only
Параметр 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 ($/) используется, если выполняется одно из следующих условий:

  • Ни одна из этих последовательностей не найдена.

  • Data равно ARGF, STDIN, STDOUT, или STDERR.

  • Поток доступен только для вывода.

Очевидно, обнаружение занимает немного времени. Set вручную, если скорость важна. Также обратите внимание, что объекты IO должны открываться в двоичном режиме на Windows, если эта функция будет использоваться, так как преобразование окончания строк может вызвать проблемы с возвращением позиции документа к исходному состоянию до считывания.

Параметр col_sep

Указывает разделитель полей типа String, который используется для разбора и генерации. Строка будет преобразована в кодировку данных перед использованием.

Значение по умолчанию:

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)
Параметр 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"

См. также Преобразователи записи

Параметр 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 отображает:

  • Индекс поля с нулевым основанием.

  • Индекс строки с единичным основанием.

  • Заголовок поля, если таковой имеется.

Хранимые преобразователи

Преобразователю может быть присвоено имя и он может быть сохранён в структуре, где методы разбора могут найти его по имени.

Структура хранения для преобразователей полей — хэш CSV::Converters. В ней есть несколько встроенных процедур преобразователей:

  • :integer: Преобразует каждый целое число, встроенное в строку, в истинное целое число.

  • :float: Преобразует каждое дробное число, встроенное в строку, в истинное число с плавающей запятой.

  • :date: Преобразует каждую строку даты в истинную дату.

  • :date_time: Преобразует каждую строку даты и времени в истинное значение DateTime.

. Этот пример создаёт процедуру преобразователя, затем сохраняет её:

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"]]

Структура хранения для преобразователей заголовков — хэш CSV::HeaderConverters, которая работает аналогичным образом. Она также содержит встроенные процедуры преобразователей:

  • :downcase: Приводит каждый заголовок к нижнему регистру.

  • :symbol: Преобразует каждый заголовок в символ.

Такой структуры хранения для преобразователей записи не существует.

Для доступа к хранимым преобразователям в неглавных Ractor'ах методам парсинга, структура хранения должна быть сначала сделана совместной. Поэтому, Ractor.make_shareable(CSV::Converters) и Ractor.make_shareable(CSV::HeaderConverters) должны быть вызваны перед созданием Ractor'ов, использующих преобразователи, хранящиеся в этих структурах. (Так как создание общих структур хранения подразумевает их заморозку, любые пользовательские преобразователи, которые должны быть использованы, должны быть добавлены сначала.)

Списки преобразователей

Список преобразователей — это массив, который может включать любые комбинации:

  • Процедуры преобразования.

  • Имена хранящихся преобразователей.

  • Вложенные списки преобразователей.

Примеры:

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"]]

Преобразователи заголовков

Преобразователи заголовков работают только с заголовками (а не с другими строками).

Существует три способа использования преобразователей заголовков; в этих примерах используется встроенный преобразователь заголовков :downcase, который преобразует каждый проанализированный заголовок в нижний регистр.

  • Опция header_converters с методом парсинга экземпляра:

    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"]
    
  • Method header_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 парсер умеет работать с кодировками. Парсер работает в кодировке Encoding объекта IO или String, из которого или в который он считывается/записывается. Ваши данные никогда не транскодируются (если вы не попросите Руби их транскодировать), а будут буквально обработаны в Encoding кодировке. Таким образом, CSV вернёт массивы или строки строк в Encoding кодировке ваших данных. Это достигается путём транскодирования самого парсера в Encoding кодировку.

Некоторые транскодирования, конечно, должны произойти, чтобы реализовать поддержку множественных кодировок. Например, :col_sep, :row_sep, и :quote_char должны быть транскодированы в соответствии с вашими данными. Надеюсь, это делает весь процесс прозрачным, так как настройки по умолчанию CSV просто должны магически работать с вашими данными. Однако, вы можете установить эти значения вручную в целевой Encoding кодировке, чтобы избежать транскодирования.

Также важно отметить, что, хотя весь основной парсер CSV теперь Encoding не зависит от кодировки, некоторые функции не зависят от неё. Например, встроенные преобразователи будут пытаться транскодировать данные в UTF-8 перед выполнением преобразований. Снова, вы можете предоставить пользовательские преобразователи, которые знают о ваших кодировках, чтобы избежать этого транскодирования. Мне просто слишком сложно поддерживать родные преобразования для всех кодировок Руби.

В любом случае, практическая сторона этого проста: убедитесь, что объекты 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 проблемы в документации методов по мере их возникновения.

Это было протестировано по возможности со всеми не «фиктивными» кодировками, которые Руби поставляет. Однако, это новый код, и в нём могут быть ошибки. Пожалуйста, не стесняйтесь сообщить о любых проблемах, которые вы обнаружите.

Константы

ConverterEncoding

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

Converters

Хэш, содержащий имена и Процедуры для встроенных конвертеров полей. См. Встроенные конвертеры полей.

Этот хэш намеренно оставлен незамороженным и может быть расширен с помощью пользовательских конвертеров полей. См. Пользовательские конвертеры полей.

DEFAULT_OPTIONS

Значения по умолчанию для параметров метода.

DateMatcher

Регулярное выражение, используемое для поиска и преобразования некоторых распространенных форматов дат.

DateTimeMatcher

Регулярное выражение, используемое для поиска и преобразования некоторых распространенных форматов дат и времени.

FieldInfo

Структура данных, содержащая детали о позиции поля в источнике данных, из которого оно было прочитано. CSV передаст эту структуру некоторым блокам, которые принимают решения, основанные на структуре поля. См. CSV.convert_fields() для примера.

index

Индекс поля в строке (нумерация с нуля).

line

Строка источника данных, из которой взята данная строка.

header

Заголовок столбца, если он доступен.

quoted?

Истина или ложь, указывает, было ли исходное значение заключено в кавычки.

HeaderConverters

Хэш, содержащий имена и Процедуры для встроенных конвертеров заголовков. См. Встроенные конвертеры заголовков.

Этот хэш намеренно оставлен незамороженным и может быть расширен с помощью пользовательских конвертеров полей. См. Пользовательские конвертеры заголовков.

VERSION

Версия установленной библиотеки.

Атрибуты

encoding[R]

:call-seq:

csv.encoding -> encoding

Возвращает кодировку, используемую для парсинга и генерации; см. Кодировки символов (M17n или Многоязычность):

CSV.new('').encoding # => #<Encoding:UTF-8>
END_OF_DOCUMENT_MARKER

Методы публичного класса

filter(in_string_or_io, **options) {|row| ... } → array_of_arrays or csv_table Показать исходный код
filter(in_string_or_io, out_string_or_io, **options) {|row| ... } → array_of_arrays or csv_table
filter(**options) {|row| ... } → array_of_arrays or csv_table
# File lib/csv.rb, line 1202
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
    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 из источника (строка, поток ввода-вывода или ARGF).

  • Вызывает заданный блок для каждой прочитанной строки:

    • Без заголовков, каждая строка — массив.

    • С заголовками, каждая строка — CSV::Row.

  • Генерирует CSV в выходной поток (строка, поток ввода-вывода или стандартный вывод).

  • Возвращает прочитанный источник:

    • Без заголовков — массив массивов.

    • С заголовками — CSV::Table.

Когда in_string_or_io задан, но out_string_or_io нет, парсит из заданного in_string_or_io и генерирует в стандартный вывод.

Входной строковый тип данных без заголовков:

in_string = "foo,0\nbar,1\nbaz,2"
CSV.filter(in_string) do |row|
  row[0].upcase!
  row[1] = - row[1].to_i
end # => [["FOO", 0], ["BAR", -1], ["BAZ", -2]]

Вывод (в стандартный вывод):

FOO,0
BAR,-1
BAZ,-2

Входной строковый тип данных с заголовками:

in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2"
CSV.filter(in_string, headers: true) do |row|
  row[0].upcase!
  row[1] = - row[1].to_i
end # => #<CSV::Table mode:col_or_row row_count:4>

Вывод (в стандартный вывод):

Name,Value
FOO,0
BAR,-1
BAZ,-2

Входной поток ввода-вывода без заголовков:

File.write('t.csv', "foo,0\nbar,1\nbaz,2")
File.open('t.csv') do |in_io|
  CSV.filter(in_io) do |row|
    row[0].upcase!
    row[1] = - row[1].to_i
  end
end # => [["FOO", 0], ["BAR", -1], ["BAZ", -2]]

Вывод (в стандартный вывод):

FOO,0
BAR,-1
BAZ,-2

Входной поток ввода-вывода с заголовками:

File.write('t.csv', "Name,Value\nfoo,0\nbar,1\nbaz,2")
File.open('t.csv') do |in_io|
  CSV.filter(in_io, headers: true) do |row|
    row[0].upcase!
    row[1] = - row[1].to_i
  end
end # => #<CSV::Table mode:col_or_row row_count:4>

Вывод (в стандартный вывод):

Name,Value
FOO,0
BAR,-1
BAZ,-2

Когда и in_string_or_io, и out_string_or_io заданы, парсит из in_string_or_io и генерирует в out_string_or_io.

Выходной строковый тип данных без заголовков:

in_string = "foo,0\nbar,1\nbaz,2"
out_string = ''
CSV.filter(in_string, out_string) do |row|
  row[0].upcase!
  row[1] = - row[1].to_i
end # => [["FOO", 0], ["BAR", -1], ["BAZ", -2]]
out_string # => "FOO,0\nBAR,-1\nBAZ,-2\n"

Выходной строковый тип данных с заголовками:

in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2"
out_string = ''
CSV.filter(in_string, out_string, headers: true) do |row|
  row[0].upcase!
  row[1] = - row[1].to_i
end # => #<CSV::Table mode:col_or_row row_count:4>
out_string # => "Name,Value\nFOO,0\nBAR,-1\nBAZ,-2\n"

Выходной поток ввода-вывода без заголовков:

in_string = "foo,0\nbar,1\nbaz,2"
File.open('t.csv', 'w') do |out_io|
  CSV.filter(in_string, out_io) do |row|
    row[0].upcase!
    row[1] = - row[1].to_i
  end
end # => [["FOO", 0], ["BAR", -1], ["BAZ", -2]]
File.read('t.csv') # => "FOO,0\nBAR,-1\nBAZ,-2\n"

Выходной поток ввода-вывода с заголовками:

in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2"
File.open('t.csv', 'w') do |out_io|
  CSV.filter(in_string, out_io, headers: true) do |row|
    row[0].upcase!
    row[1] = - row[1].to_i
  end
end # => #<CSV::Table mode:col_or_row row_count:4>
File.read('t.csv') # => "Name,Value\nFOO,0\nBAR,-1\nBAZ,-2\n"

Если ни in_string_or_io, ни out_string_or_io не заданы, парсит из ARGF и генерирует в стандартный вывод.

Без заголовков:

# Put Ruby code into a file.
ruby = <<-EOT
  require 'csv'
  CSV.filter do |row|
    row[0].upcase!
    row[1] = - row[1].to_i
  end
EOT
File.write('t.rb', ruby)
# Put some CSV into a file.
File.write('t.csv', "foo,0\nbar,1\nbaz,2")
# Run the Ruby code with CSV filename as argument.
system(Gem.ruby, "t.rb", "t.csv")

Вывод (в стандартный вывод):

FOO,0
BAR,-1
BAZ,-2

С заголовками:

# Put Ruby code into a file.
ruby = <<-EOT
  require 'csv'
  CSV.filter(headers: true) do |row|
    row[0].upcase!
    row[1] = - row[1].to_i
  end
EOT
File.write('t.rb', ruby)
# Put some CSV into a file.
File.write('t.csv', "Name,Value\nfoo,0\nbar,1\nbaz,2")
# Run the Ruby code with CSV filename as argument.
system(Gem.ruby, "t.rb", "t.csv")

Вывод (в стандартный вывод):

Name,Value
FOO,0
BAR,-1
BAZ,-2

Аргументы:

  • Аргумент in_string_or_io должен быть строкой или потоком ввода-вывода.

  • Аргумент out_string_or_io должен быть строкой или потоком ввода-вывода.

  • Аргументы **options должны быть именованными опциями. См. Опции для парсинга.

foreach(path_or_io, mode='r', **options) {|row| ... ) Показать исходный код
foreach(path_or_io, mode='r', **options) → new_enumerator
# File lib/csv.rb, line 1332
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_or_io.

Входной путь без заголовков:

string = "foo,0\nbar,1\nbaz,2\n"
in_path = 't.csv'
File.write(in_path, string)
CSV.foreach(in_path) {|row| p row }

Вывод:

["foo", "0"]
["bar", "1"]
["baz", "2"]

Входной путь с заголовками:

string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
in_path = 't.csv'
File.write(in_path, string)
CSV.foreach(in_path, headers: true) {|row| p row }

Вывод:

<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"
path = 't.csv'
File.write(path, string)
File.open('t.csv') do |in_io|
  CSV.foreach(in_io) {|row| p row }
end

Вывод:

["foo", "0"]
["bar", "1"]
["baz", "2"]

Входной поток ввода-вывода с заголовками:

string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)
File.open('t.csv') do |in_io|
  CSV.foreach(in_io, headers: true) {|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"
path = 't.csv'
File.write(path, string)
CSV.foreach(path) # => #<Enumerator: CSV:foreach("t.csv", "r")>

Аргументы:

  • Аргумент path_or_io должен быть путём к файлу или потоком ввода-вывода.

  • Аргумент mode, если задан, должен быть режимом файла. См. Режимы доступа.

  • Аргументы **options должны быть именованными опциями. См. Опции для парсинга.

  • Этот метод необязательно принимает дополнительную опцию :encoding, которую можно использовать для указания кодировки Encoding данных, считываемых из path или io.

    Необходимо предоставить, если ваши данные не в кодировке, указанной в Encoding::default_external. Парсинг использует её для определения способа парсинга данных. Можно указать вторую Encoding для транскодирования данных при чтении. Например,

    encoding: 'UTF-32BE:UTF-8'

    считает данные в формате UTF-32BE из файла, но транскодирует их в UTF-8 перед парсингом.

generate(csv_string, **options) {|csv| ... } Показать исходный код
generate(**options) {|csv| ... }
# File lib/csv.rb, line 1398
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)
generate_line(ary) Показать исходный код
generate_line(ary, **options)
# File lib/csv.rb, line 1446
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)
generate_lines(rows) Показать исходный код
generate_lines(rows, **options)
# File lib/csv.rb, line 1501
def generate_lines(rows, **options)
  self.generate(**options) do |csv|
    rows.each do |row|
      csv << row
    end
  end
end

Возвращает строку, созданную путём генерации CSV, используя указанные options.

Аргумент rows должен быть массивом строк. Row — массив строк или CSV::Row.

Специальные опции:

  • Опция :row_sep по умолчанию "\n" в Ruby 3.0 и выше и $INPUT_RECORD_SEPARATOR ($/) в противном случае:

    $INPUT_RECORD_SEPARATOR # => "\n"
    
  • Этот метод принимает дополнительную опцию :encoding, которая устанавливает базовую Encoding для вывода. Этот метод попытается определить вашу Encoding из первого не-nil поля в row, если это возможно, но вам может потребоваться использовать этот параметр как резервный вариант.

Для других options, см. Опции для генерации.

Возвращает строку, сгенерированную из

CSV.generate_lines([['foo', '0'], ['bar', '1'], ['baz', '2']]) # => "foo,0\nbar,1\nbaz,2\n"

Выбрасывает исключение

# Raises NoMethodError (undefined method `each' for :foo:Symbol)
CSV.generate_lines(:foo)
instance(string, **options) Показать исходный код
instance(io = $stdout, **options)
instance(string, **options) {|csv| ... }
instance(io = $stdout, **options) {|csv| ... }
# File lib/csv.rb, line 1006
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)

  # 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
new(string) Показать исходный код
new(io)
new(string, **options)
new(io, **options)
# File lib/csv.rb, line 1905
def initialize(data,
               col_sep: ",",
               row_sep: :auto,
               quote_char: '"',
               field_size_limit: nil,
               max_field_size: 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)
    if encoding
      if encoding.is_a?(String)
        data_external_encoding, data_internal_encoding = encoding.split(":", 2)
        if data_internal_encoding
          data = data.encode(data_internal_encoding, data_external_encoding)
        else
          data = data.dup.force_encoding(data_external_encoding)
        end
      else
        data = data.dup.force_encoding(encoding)
      end
    end
    @io = StringIO.new(data)
  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

  if max_field_size.nil? and field_size_limit
    max_field_size = field_size_limit - 1
  end
  @parser_options = {
    column_separator: col_sep,
    row_separator: row_sep,
    quote_character: quote_char,
    max_field_size: max_field_size,
    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)
open(file_path, mode = "rb", **options ) → new_csv Показать исходный код
open(io, mode = "rb", **options ) → new_csv
open(file_path, mode = "rb", **options ) { |csv| ... } → object
open(io, mode = "rb", **options ) { |csv| ... } → object
# File lib/csv.rb, line 1581
def open(filename, mode="r", **options)
  # wrap a File opened with the remaining +args+ with no newline
  # decorator
  file_opts = options.dup
  unless file_opts.key?(:newline)
    file_opts[:universal_newline] ||= false
  end
  options.delete(:invalid)
  options.delete(:undef)
  options.delete(:replace)
  options.delete_if {|k, _| /newline\z/.match?(k)}

  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

Возможные элементы опций:

keyword 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)
parse(string) → array_of_arrays Показать исходный код
parse(io) → array_of_arrays
parse(string, headers: ..., **options) → csv_table
parse(io, headers: ..., **options) → csv_table
parse(string, **options) {|row| ... }
parse(io, **options) {|row| ... }
# File lib/csv.rb, line 1732
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)
parse_line(string) → new_array or nil Показать исходный код
parse_line(io) → new_array or nil
parse_line(string, **options) → new_array or nil
parse_line(io, **options) → new_array or nil
parse_line(string, headers: true, **options) → csv_row or nil
parse_line(io, headers: true, **options) → csv_row or nil
# File lib/csv.rb, line 1805
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)
read(source, **options) → array_of_arrays Показать исходный код
read(source, headers: true, **options) → csv_table
# File lib/csv.rb, line 1829
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>
readlines(source, **options) Показать исходный код
# File lib/csv.rb, line 1837
def readlines(path, **options)
  read(path, **options)
end

Псевдоним для CSV.read.

table(source, **options) Показать исходный код
# File lib/csv.rb, line 1856
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>

Общедоступные методы экземпляра

csv << row → self Показать исходный код
# File lib/csv.rb, line 2372
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
Также алиас: add_row, puts
add_row
Псевдоним для: <<
binmode?() Показать исходный код
# File lib/csv.rb, line 2261
def binmode?
  if @io.respond_to?(:binmode?)
    @io.binmode?
  else
    false
  end
end
col_sep → string Показать исходный код
# File lib/csv.rb, line 2009
def col_sep
  parser.column_separator
end

Возвращает закодированный разделитель столбцов; используется для разбора и записи; см. {Параметр col_sep}:

CSV.new('').col_sep # => ","
convert(converter_name) → array_of_procs Показать исходный код
convert {|field, field_info| ... } → array_of_procs
# File lib/csv.rb, line 2443
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>]

Блок не обязательно должен возвращать строковый объект:

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
converters → array Показать исходный код
# File lib/csv.rb, line 2082
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, чтобы использовать этот метод.

each → enumerator Показать исходный код
each {|row| ...}
# File lib/csv.rb, line 2554
def each(&block)
  return to_enum(__method__) unless block_given?
  begin
    while true
      yield(parser_enumerator.next)
    end
  rescue StopIteration
  end
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
eof()
Псевдоним для: eof?
eof?() Показать исходный код
# File lib/csv.rb, line 2297
def eof?
  return false if @eof_error
  begin
    parser_enumerator.peek
    false
  rescue MalformedCSVError => error
    @eof_error = error
    false
  rescue StopIteration
    true
  end
end
Также алиас: eof
field_size_limit → integer or nil Показать исходный код
# File lib/csv.rb, line 2041
def field_size_limit
  parser.field_size_limit
end

Возвращает ограничение размера поля; используется для разбора; см. {Параметр field_size_limit}:

CSV.new('').field_size_limit # => nil

Устарело начиная с 3.2.3. Используйте max_field_size вместо этого.

flock(*args) Показать исходный код
# File lib/csv.rb, line 2269
def flock(*args)
  raise NotImplementedError unless @io.respond_to?(:flock)
  @io.flock(*args)
end
force_quotes? → true or false Показать исходный код
# File lib/csv.rb, line 2172
def force_quotes?
  @writer_options[:force_quotes]
end

Возвращает значение, определяющее, должны ли все выходные поля быть заключены в кавычки; используется для генерации; см. {Параметр force_quotes}:

CSV.new('').force_quotes? # => false
gets
Псевдоним для: shift
header_convert(name = nil, &converter) Показать исходный код
# File lib/csv.rb, line 2509
def header_convert(name = nil, &converter)
  header_fields_converter.add_converter(name, &converter)
end

Блок не обязательно должен возвращать строковый объект:

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
header_converters → array Показать исходный код
# File lib/csv.rb, line 2148
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, чтобы использовать этот метод.

header_row? → true or false Показать исходный код
# File lib/csv.rb, line 2631
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?
headers → object Показать исходный код
# File lib/csv.rb, line 2106
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
inspect → string Показать исходный код
# File lib/csv.rb, line 2690
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>"
ioctl(*args) Показать исходный код
# File lib/csv.rb, line 2274
def ioctl(*args)
  raise NotImplementedError unless @io.respond_to?(:ioctl)
  @io.ioctl(*args)
end
liberal_parsing? → true или false Показать исходный код
# File lib/csv.rb, line 2182
def liberal_parsing?
  parser.liberal_parsing?
end

Возвращает значение, определяющее, как обрабатывать некорректный ввод; используется для парсинга; см. {Параметр liberal_parsing}:

CSV.new('').liberal_parsing? # => false
line → массив Показать исходный код
# File lib/csv.rb, line 2247
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"]
line_no → целое число Показать исходный код
# File lib/csv.rb, line 2223
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
max_field_size → целое число или nil Показать исходный код
# File lib/csv.rb, line 2053
def max_field_size
  parser.max_field_size
end

Возвращает ограничение размера поля; используется для парсинга; см. {Параметр max_field_size}:

CSV.new('').max_field_size # => nil

С версии 3.2.3.

path() Показать исходный код
# File lib/csv.rb, line 2279
def path
  @io.path if @io.respond_to?(:path)
end
puts
Псевдоним для: <<
quote_char → символ Показать исходный код
# File lib/csv.rb, line 2029
def quote_char
  parser.quote_character
end

Возвращает закодированный символ кавычки; используется для парсинга и записи; см. {Параметр quote_char}:

CSV.new('').quote_char # => "\""
read → массив или csv_table Показать исходный код
# File lib/csv.rb, line 2595
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
Также алиас для: readlines
readline
Псевдоним для: shift
readlines
Псевдоним для: read
return_headers? → true или false Показать исходный код
# File lib/csv.rb, line 2124
def return_headers?
  parser.return_headers?
end

Возвращает значение, определяющее, должны ли возвращаться заголовки; используется для парсинга; см. {Параметр return_headers}:

CSV.new('').return_headers? # => false
rewind() Показать исходный код
# File lib/csv.rb, line 2312
def rewind
  @parser = nil
  @parser_enumerator = nil
  @eof_error = nil
  @writer.rewind if @writer
  @io.rewind
end

Перематывает подлежащий IO объект и сбрасывает счётчик строк CSV.

row_sep → строка Показать исходный код
# File lib/csv.rb, line 2019
def row_sep
  parser.row_separator
end

Возвращает закодированный разделитель строк; используется для парсинга и записи; см. {Параметр row_sep}:

CSV.new('').row_sep # => "\n"
shift → массив, csv_row или nil Показать исходный код
# File lib/csv.rb, line 2668
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
Также алиас для: gets, readline
skip_blanks? → true или false Показать исходный код
# File lib/csv.rb, line 2161
def skip_blanks?
  parser.skip_blanks?
end

Возвращает значение, определяющее, должны ли пустые строки игнорироваться; используется для парсинга; см. {Параметр skip_blanks}:

CSV.new('').skip_blanks? # => false
skip_lines → regexp или nil Показать исходный код
# File lib/csv.rb, line 2063
def skip_lines
  parser.skip_lines
end

Возвращает Regexp, используемый для идентификации комментариев; используется для парсинга; см. {Параметр skip_lines}:

CSV.new('').skip_lines # => nil
stat(*args) Показать исходный код
# File lib/csv.rb, line 2283
def stat(*args)
  raise NotImplementedError unless @io.respond_to?(:stat)
  @io.stat(*args)
end
to_i() Показать исходный код
# File lib/csv.rb, line 2288
def to_i
  raise NotImplementedError unless @io.respond_to?(:to_i)
  @io.to_i
end
to_io() Показать исходный код
# File lib/csv.rb, line 2293
def to_io
  @io.respond_to?(:to_io) ? @io.to_io : @io
end
unconverted_fields? → объект Показать исходный код
# File lib/csv.rb, line 2096
def unconverted_fields?
  parser.unconverted_fields?
end

Возвращает значение, определяющее, должны ли быть доступны необработанные поля; используется для парсинга; см. {Параметр unconverted_fields}:

CSV.new('').unconverted_fields? # => nil
write_headers? → true или false Показать исходный код
# File lib/csv.rb, line 2134
def write_headers?
  @writer_options[:write_headers]
end

Возвращает значение, определяющее, должны ли записываться заголовки; используется для генерации; см. {Параметр write_headers}:

CSV.new('').write_headers? # => nil

Приватные методы экземпляра

build_fields_converter(initial_converters, options) Показать исходный код
# File lib/csv.rb, line 2822
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
build_header_fields_converter() Показать исходный код
# File lib/csv.rb, line 2804
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
build_parser_fields_converter() Показать исходный код
# File lib/csv.rb, line 2792
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
build_writer_fields_converter() Показать исходный код
# File lib/csv.rb, line 2817
def build_writer_fields_converter
  build_fields_converter(@initial_write_converters,
                         @write_fields_converter_options)
end
convert_fields(fields, headers = false) Показать исходный код
# File lib/csv.rb, line 2767
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, прерывает цепочку преобразований для этого поля. Это в первую очередь служит оптимизацией.

determine_encoding(encoding, internal_encoding) Показать исходный код
# File lib/csv.rb, line 2730
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
header_fields_converter() Показать исходный код
# File lib/csv.rb, line 2800
def header_fields_converter
  @header_fields_converter ||= build_header_fields_converter
end
normalize_converters(converters) Показать исходный код
# File lib/csv.rb, line 2745
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
parser() Показать исходный код
# File lib/csv.rb, line 2830
def parser
  @parser ||= Parser.new(@io, parser_options)
end
parser_enumerator() Показать исходный код
# File lib/csv.rb, line 2839
def parser_enumerator
  @parser_enumerator ||= parser.parse
end
parser_fields_converter() Показать исходный код
# File lib/csv.rb, line 2788
def parser_fields_converter
  @parser_fields_converter ||= build_parser_fields_converter
end
parser_options() Показать исходный код
# File lib/csv.rb, line 2834
def parser_options
  @parser_options.merge(header_fields_converter: header_fields_converter,
                        fields_converter: parser_fields_converter)
end
raw_encoding() Показать исходный код
# File lib/csv.rb, line 2778
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.

writer() Показать исходный код
# File lib/csv.rb, line 2843
def writer
  @writer ||= Writer.new(@io, writer_options)
end
writer_fields_converter() Показать исходный код
# File lib/csv.rb, line 2813
def writer_fields_converter
  @writer_fields_converter ||= build_writer_fields_converter
end
writer_options() Показать исходный код
# File lib/csv.rb, line 2847
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.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API