Spec-Zone.ru › Ruby 3.1

класс CSV

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

CSV

Данные CSV (comma-separated variables) представляют собой текстовое представление таблицы:

  • Разделитель строк определяет строки таблицы. Обычный разделитель строк — символ новой строки "\n".

  • Разделитель столбцов определяет поля в строке. Обычный разделитель столбцов — запятая ",".

Эта строка CSV с разделителем строк "\n" и разделителем столбцов ",", содержит три строки и два столбца:

"foo,0\nbar,1\nbaz,2\n"

Несмотря на название CSV, в представлении CSV можно использовать разные разделители.

Для получения более подробной информации о таблицах, см. статью Википедии «Таблица (информация)», особенно раздел «Простая таблица»

Класс CSV

Class Класс CSV предоставляет методы для:

  • Разбора данных CSV из объекта String, файла (через его путь) или объекта IO.

  • Генерации данных CSV в объект String.

Чтобы использовать CSV:

require 'csv'

Все примеры здесь предполагают, что это сделано.

Упрощение

Объект CSV имеет десятки методов экземпляров, которые обеспечивают тонкую настройку разбора и генерации данных CSV. Однако для многих задач подойдут более простые подходы.

В этом разделе обобщены статические методы в CSV, которые позволяют выполнять разбор и генерацию без явного создания объектов CSV. Для получения подробностей см. ссылки.

Простой разбор

Методы разбора обычно возвращают один из следующих вариантов:

  • Массив массивов строк:

    • Внешний массив — это вся «таблица».

    • Каждый внутренний массив — это строка.

    • Каждая строка — это поле.

  • Объект CSV::Table. Для получения подробностей см. CSV с заголовками.

Разбор строки

Входные данные для разбора могут быть строкой:

string = "foo,0\nbar,1\nbaz,2\n"

Метод CSV.parse возвращает все данные CSV:

CSV.parse(string) # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]

Метод CSV.parse_line возвращает только первую строку:

CSV.parse_line(string) # => ["foo", "0"]

CSV расширяет класс String методом экземпляра String#parse_csv, который также возвращает только первую строку:

string.parse_csv # => ["foo", "0"]

Разбор через путь к файлу

Входные данные для разбора могут быть в файле:

string = "foo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)

Метод CSV.read возвращает все данные CSV:

CSV.read(path) # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]

Метод CSV.foreach перебирает, передавая каждую строку в заданный блок:

CSV.foreach(path) do |row|
  p row
end

Вывод:

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

Метод CSV.table возвращает все данные CSV как объект CSV::Table:

CSV.table(path) # => #<CSV::Table mode:col_or_row row_count:3>

Разбор из открытого потока IO

Входные данные для разбора могут находиться в открытом потоке IO:

Метод CSV.read возвращает все данные CSV:

File.open(path) do |file|
  CSV.read(file)
end # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]

Так же, как и метод CSV.parse:

File.open(path) do |file|
  CSV.parse(file)
end # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]

Метод CSV.parse_line возвращает только первую строку:

File.open(path) do |file|
 CSV.parse_line(file)
end # => ["foo", "0"]

Метод CSV.foreach перебирает, передавая каждую строку в заданный блок:

File.open(path) do |file|
  CSV.foreach(file) do |row|
    p row
  end
end

Вывод:

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

Метод CSV.table возвращает все данные CSV как объект CSV::Table:

File.open(path) do |file|
  CSV.table(file)
end # => #<CSV::Table mode:col_or_row row_count:3>

Простая генерация

Метод CSV.generate возвращает строку; в этом примере используется метод CSV#<< для добавления строк, которые должны быть сгенерированы:

output_string = CSV.generate do |csv|
  csv << ['foo', 0]
  csv << ['bar', 1]
  csv << ['baz', 2]
end
output_string # => "foo,0\nbar,1\nbaz,2\n"

Метод CSV.generate_line возвращает строку, содержащую единственную строку, сконструированную из массива:

CSV.generate_line(['foo', '0']) # => "foo,0\n"

CSV расширяет класс Array методом экземпляра Array#to_csv, который преобразует массив в строку:

['foo', '0'].to_csv # => "foo,0\n"

«Фильтрация» CSV

Метод CSV.filter предоставляет фильтр в стиле Unix для данных CSV. Входные данные обрабатываются для формирования выходных данных:

in_string = "foo,0\nbar,1\nbaz,2\n"
out_string = ''
CSV.filter(in_string, out_string) do |row|
  row[0] = row[0].upcase
  row[1] *= 4
end
out_string # => "FOO,0000\nBAR,1111\nBAZ,2222\n"

Объекты CSV

Существует три способа создания объекта CSV:

  • Метод CSV.new возвращает новый объект CSV.

  • Метод CSV.instance возвращает новый или кэшированный объект CSV.

  • Метод CSV() также возвращает новый или кэшированный объект CSV.

Методы экземпляра

CSV имеет три группы методов экземпляра:

  • Свои внутренне определенные методы экземпляра.

  • Методы, включенные модулем Enumerable.

  • Методы, делегированные классу IO. См. ниже.

Делегированные методы

Для удобства объект CSV делегирует многие методы классу IO. (Некоторые из них имеют оберточную «защитную кодовую оболочку» в CSV.) Вы можете вызвать:

  • IO#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: Указывает максимальный размер поля, разрешенный для обработки.

  • converters: Указывает преобразователи полей, которые нужно использовать.

  • unconverted_fields: Указывает, будут ли доступны необработанные поля.

  • headers: Указывает, содержит ли данные заголовки, или указывает сами заголовки.

  • return_headers: Указывает, нужно ли возвращать заголовки.

  • header_converters: Указывает преобразователи заголовков, которые нужно использовать.

  • skip_blanks: Указывает, должны ли игнорироваться пустые строки.

  • skip_lines: Указывает, как распознаются строки комментариев.

  • strip: Указывает, нужно ли удалять начальные и конечные пробелы из полей. Это должно быть совместимо с col_sep; если это не так, будет возбуждено исключение ArgumentError.

  • liberal_parsing: Указывает, должна ли программа CSV пытаться анализировать несоответствующие данные.

  • nil_value: Указывает объект, который нужно подставить для каждого нулевого (без текста) поля.

  • empty_value: Указывает объект, который нужно подставить для каждого пустого поля.

Параметр row_sep

Указывает разделитель строк, строку или символ :auto (см. ниже), используемые как для разбора, так и для генерации.

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

CSV::DEFAULT_OPTIONS.fetch(:row_sep) # => :auto

Когда row_sep — это строка, эта строка становится разделителем строк. Строка String будет преобразована в кодировку данных Encoding перед использованием.

Использование "\n":

row_sep = "\n"
str = CSV.generate(row_sep: row_sep) do |csv|
  csv << [:foo, 0]
  csv << [:bar, 1]
  csv << [:baz, 2]
end
str # => "foo,0\nbar,1\nbaz,2\n"
ary = CSV.parse(str)
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]

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

row_sep = '|'
str = CSV.generate(row_sep: row_sep) do |csv|
  csv << [:foo, 0]
  csv << [:bar, 1]
  csv << [:baz, 2]
end
str # => "foo,0|bar,1|baz,2|"
ary = CSV.parse(str, row_sep: row_sep)
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]

Использование -- (два дефиса):

row_sep = '--'
str = CSV.generate(row_sep: row_sep) do |csv|
  csv << [:foo, 0]
  csv << [:bar, 1]
  csv << [:baz, 2]
end
str # => "foo,0--bar,1--baz,2--"
ary = CSV.parse(str, row_sep: row_sep)
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]

Использование '' (пустая строка):

row_sep = ''
str = CSV.generate(row_sep: row_sep) do |csv|
  csv << [:foo, 0]
  csv << [:bar, 1]
  csv << [:baz, 2]
end
str # => "foo,0bar,1baz,2"
ary = CSV.parse(str, row_sep: row_sep)
ary # => [["foo", "0bar", "1baz", "2"]]

Когда row_sep — это символ :auto (по умолчанию), при генерации используется "\n" в качестве разделителя строк:

str = CSV.generate do |csv|
  csv << [:foo, 0]
  csv << [:bar, 1]
  csv << [:baz, 2]
end
str # => "foo,0\nbar,1\nbaz,2\n"

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

Автообнаружение читает данные вперёд, в поисках следующей последовательности \r\n, \n, или \r. Последовательность будет выбрана, даже если она встречается в цитируемом поле, предполагая, что там будут те же самые окончания строк.

Пример:

str = CSV.generate do |csv|
  csv << [:foo, 0]
  csv << [:bar, 1]
  csv << [:baz, 2]
end
str # => "foo,0\nbar,1\nbaz,2\n"
ary = CSV.parse(str)
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]

По умолчанию используется значение $INPUT_RECORD_SEPARATOR ($/) если выполняется одно из следующих условий:

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

  • Данные ARGF, STDIN, STDOUT, или STDERR.

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

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

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

row_sep = BasicObject.new
# Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
CSV.generate(ary, row_sep: row_sep)
# Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
CSV.parse(str, row_sep: row_sep)
Параметр col_sep

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

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

CSV::DEFAULT_OPTIONS.fetch(:col_sep) # => "," (comma)

Использование значения по умолчанию (запятая):

str = CSV.generate do |csv|
  csv << [:foo, 0]
  csv << [:bar, 1]
  csv << [:baz, 2]
end
str # => "foo,0\nbar,1\nbaz,2\n"
ary = CSV.parse(str)
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]

Использование : (двоеточие):

col_sep = ':'
str = CSV.generate(col_sep: col_sep) do |csv|
  csv << [:foo, 0]
  csv << [:bar, 1]
  csv << [:baz, 2]
end
str # => "foo:0\nbar:1\nbaz:2\n"
ary = CSV.parse(str, col_sep: col_sep)
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]

Использование :: (два двоеточия):

col_sep = '::'
str = CSV.generate(col_sep: col_sep) do |csv|
  csv << [:foo, 0]
  csv << [:bar, 1]
  csv << [:baz, 2]
end
str # => "foo::0\nbar::1\nbaz::2\n"
ary = CSV.parse(str, col_sep: col_sep)
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]

Использование '' (пустая строка):

col_sep = ''
str = CSV.generate(col_sep: col_sep) do |csv|
  csv << [:foo, 0]
  csv << [:bar, 1]
  csv << [:baz, 2]
end
str # => "foo0\nbar1\nbaz2\n"

Вызовет исключение при разборе с пустой строкой:

col_sep = ''
# Raises ArgumentError (:col_sep must be 1 or more characters: "")
CSV.parse("foo0\nbar1\nbaz2\n", col_sep: col_sep)

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

col_sep = BasicObject.new
# Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
CSV.generate(line, col_sep: col_sep)
# Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
CSV.parse(str, col_sep: col_sep)
Параметр quote_char

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

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

CSV::DEFAULT_OPTIONS.fetch(:quote_char) # => "\"" (double quote)

Это полезно для приложения, которое неправильно использует ' (одинарную кавычку) для цитирования полей вместо правильной " (двойной кавычки).

Использование значения по умолчанию (двойная кавычка):

str = CSV.generate do |csv|
  csv << ['foo', 0]
  csv << ["'bar'", 1]
  csv << ['"baz"', 2]
end
str # => "foo,0\n'bar',1\n\"\"\"baz\"\"\",2\n"
ary = CSV.parse(str)
ary # => [["foo", "0"], ["'bar'", "1"], ["\"baz\"", "2"]]

Использование ' (одинарная кавычка):

quote_char = "'"
str = CSV.generate(quote_char: quote_char) do |csv|
  csv << ['foo', 0]
  csv << ["'bar'", 1]
  csv << ['"baz"', 2]
end
str # => "foo,0\n'''bar''',1\n\"baz\",2\n"
ary = CSV.parse(str, quote_char: quote_char)
ary # => [["foo", "0"], ["'bar'", "1"], ["\"baz\"", "2"]]

Вызовет исключение, если длина строки больше 1:

# Raises ArgumentError (:quote_char has to be nil or a single character String)
CSV.new('', quote_char: 'xx')

Вызовет исключение, если значение не является строкой:

# Raises ArgumentError (:quote_char has to be nil or a single character String)
CSV.new('', quote_char: :foo)
Параметр field_size_limit

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

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

CSV::DEFAULT_OPTIONS.fetch(:field_size_limit) # => nil

Это максимальный размер, до которого CSV будет читать вперёд, в поисках закрывающей кавычки для поля. (На самом деле, он читает до первой новой строки после этого размера.) Если кавычка не будет найдена в пределах ограничения, CSV вызовет MalformedCSVError, предполагая, что данные некорректны. Вы можете использовать это ограничение, чтобы предотвратить DoS-атаки на парсер. Однако это ограничение может привести к отказу от разбора корректных данных; поэтому значение по умолчанию составляет nil (без ограничения).

Для примеров в этом разделе:

str = <<~EOT
  "a","b"
  "
  2345
  ",""
EOT
str # => "\"a\",\"b\"\n\"\n2345\n\",\"\"\n"

Использование значения по умолчанию nil:

ary = CSV.parse(str)
ary # => [["a", "b"], ["\n2345\n", ""]]

Использование 50:

field_size_limit = 50
ary = CSV.parse(str, field_size_limit: field_size_limit)
ary # => [["a", "b"], ["\n2345\n", ""]]

Вызовет исключение, если поле слишком длинное:

big_str = "123456789\n" * 1024
# Raises CSV::MalformedCSVError (Field size exceeded in line 1.)
CSV.parse('valid,fields,"' + big_str + '"', field_size_limit: 2048)
Параметр converters

Указывает преобразователи, используемые при разборе полей. См. Преобразователи полей

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

CSV::DEFAULT_OPTIONS.fetch(:converters) # => nil

Значение может быть именем преобразователя поля (см. Предопределённые преобразователи):

str = '1,2,3'
# Without a converter
array = CSV.parse_line(str)
array # => ["1", "2", "3"]
# With built-in converter :integer
array = CSV.parse_line(str, converters: :integer)
array # => [1, 2, 3]

Значение может быть списком преобразователей (см. Списки преобразователей):

str = '1,3.14159'
# Without converters
array = CSV.parse_line(str)
array # => ["1", "3.14159"]
# With built-in converters
array = CSV.parse_line(str, converters: [:integer, :float])
array # => [1, 3.14159]

Значение может быть пользовательским преобразователем Proc (см. Пользовательские преобразователи полей):

str = ' foo  ,  bar  ,  baz  '
# Without a converter
array = CSV.parse_line(str)
array # => [" foo  ", "  bar  ", "  baz  "]
# With a custom converter
array = CSV.parse_line(str, converters: proc {|field| field.strip })
array # => ["foo", "bar", "baz"]

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

Вызовет исключение, если преобразователь не является именем преобразователя или Proc:

str = 'foo,0'
# Raises NoMethodError (undefined method `arity' for nil:NilClass)
CSV.parse(str, converters: :foo)
Параметр unconverted_fields

Указывает булево значение, определяющее, доступны ли значения полей без преобразования.

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

CSV::DEFAULT_OPTIONS.fetch(:unconverted_fields) # => nil

Значения полей без преобразования — это значения, найденные в исходных данных до любого преобразования, выполненного с помощью параметра converters.

Когда параметр unconverted_fields имеет значение true, каждый возвращаемый ряд (массив или CSV::Row) имеет дополнительный метод unconverted_fields, который возвращает значения полей без преобразования:

str = <<-EOT
foo,0
bar,1
baz,2
EOT
# Without unconverted_fields
csv = CSV.parse(str, converters: :integer)
csv # => [["foo", 0], ["bar", 1], ["baz", 2]]
csv.first.respond_to?(:unconverted_fields) # => false
# With unconverted_fields
csv = CSV.parse(str, converters: :integer, unconverted_fields: true)
csv # => [["foo", 0], ["bar", 1], ["baz", 2]]
csv.first.respond_to?(:unconverted_fields) # => true
csv.first.unconverted_fields # => ["foo", "0"]
Параметр headers

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

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

CSV::DEFAULT_OPTIONS.fetch(:headers) # => false

Без headers:

str = <<-EOT
Name,Count
foo,0
bar,1
bax,2
EOT
csv = CSV.new(str)
csv # => #<CSV io_type:StringIO encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
csv.headers # => nil
csv.shift # => ["Name", "Count"]

Если установлено значение true или символ :first_row, первая строка данных обрабатывается как строка заголовков:

str = <<-EOT
Name,Count
foo,0
bar,1
bax,2
EOT
csv = CSV.new(str, headers: true)
csv # => #<CSV io_type:StringIO encoding:UTF-8 lineno:2 col_sep:"," row_sep:"\n" quote_char:"\"" headers:["Name", "Count"]>
csv.headers # => ["Name", "Count"]
csv.shift # => #<CSV::Row "Name":"bar" "Count":"1">

Если установлено значение массива, элементы массива обрабатываются как заголовки:

str = <<-EOT
foo,0
bar,1
bax,2
EOT
csv = CSV.new(str, headers: ['Name', 'Count'])
csv
csv.headers # => ["Name", "Count"]
csv.shift # => #<CSV::Row "Name":"bar" "Count":"1">

Если установлено строковое значение str, вызывается метод CSV::parse_line(str, options) с текущим options, а возвращаемый массив обрабатывается как заголовки:

str = <<-EOT
foo,0
bar,1
bax,2
EOT
csv = CSV.new(str, headers: 'Name,Count')
csv
csv.headers # => ["Name", "Count"]
csv.shift # => #<CSV::Row "Name":"bar" "Count":"1">
Параметр return_headers

Указывает булево значение, определяющее, возвращает ли метод shift строку заголовков или игнорирует её.

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

CSV::DEFAULT_OPTIONS.fetch(:return_headers) # => false

Примеры:

str = <<-EOT
Name,Count
foo,0
bar,1
bax,2
EOT
# Without return_headers first row is str.
csv = CSV.new(str, headers: true)
csv.shift # => #<CSV::Row "Name":"foo" "Count":"0">
# With return_headers first row is headers.
csv = CSV.new(str, headers: true, return_headers: true)
csv.shift # => #<CSV::Row "Name":"Name" "Count":"Count">
Параметр header_converters

Указывает преобразователи, используемые при разборе заголовков. См. Преобразователи заголовков

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

CSV::DEFAULT_OPTIONS.fetch(:header_converters) # => nil

Функционально идентично параметру converters, за исключением:

  • Преобразователи применяются только к строке заголовков.

  • Встроенные преобразователи заголовков — это :downcase и :symbol.

Этот раздел предполагает предварительное выполнение:

str = <<-EOT
Name,Value
foo,0
bar,1
baz,2
EOT
# With no header converter
table = CSV.parse(str, headers: true)
table.headers # => ["Name", "Value"]

Значение может быть именем преобразователя заголовков (см. Предопределённые преобразователи):

table = CSV.parse(str, headers: true, header_converters: :downcase)
table.headers # => ["name", "value"]

Значение может быть списком преобразователей (см. Списки преобразователей):

header_converters = [:downcase, :symbol]
table = CSV.parse(str, headers: true, header_converters: header_converters)
table.headers # => [:name, :value]

Значение может быть пользовательским преобразователем Proc (см. Пользовательские преобразователи заголовков):

upcase_converter = proc {|field| field.upcase }
table = CSV.parse(str, headers: true, header_converters: upcase_converter)
table.headers # => ["NAME", "VALUE"]

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

Параметр skip_blanks

Указывает булево значение, определяющее, будут ли игнорироваться пустые строки во входных данных; строка, содержащая разделитель столбцов, не считается пустой.

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

CSV::DEFAULT_OPTIONS.fetch(:skip_blanks) # => false

См. также параметр skiplines.

Для примеров в этом разделе:

str = <<-EOT
foo,0

bar,1
baz,2

,
EOT

Использование значения по умолчанию, false:

ary = CSV.parse(str)
ary # => [["foo", "0"], [], ["bar", "1"], ["baz", "2"], [], [nil, nil]]

Использование true:

ary = CSV.parse(str, skip_blanks: true)
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"], [nil, nil]]

Использование истинного значения:

ary = CSV.parse(str, skip_blanks: :foo)
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"], [nil, nil]]
Параметр skip_lines

Указывает объект для идентификации строк комментариев во вводе, которые будут проигнорированы:

  • Если Regexp, игнорирует строки, которые ему соответствуют.

  • Если строка, преобразует её в Regexp, игнорирует строки, которые ему соответствуют.

  • Если nil, ни одна строка не считается комментарием.

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

CSV::DEFAULT_OPTIONS.fetch(:skip_lines) # => nil

Для примеров в этом разделе:

str = <<-EOT
# Comment
foo,0
bar,1
baz,2
# Another comment
EOT
str # => "# Comment\nfoo,0\nbar,1\nbaz,2\n# Another comment\n"

Использование значения по умолчанию, nil:

ary = CSV.parse(str)
ary # => [["# Comment"], ["foo", "0"], ["bar", "1"], ["baz", "2"], ["# Another comment"]]

Использование Regexp:

ary = CSV.parse(str, skip_lines: /^#/)
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]

Использование строки:

ary = CSV.parse(str, skip_lines: '#')
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]

Вызовет исключение, если задан объект, который не является Regexp, строкой или nil:

# Raises ArgumentError (:skip_lines has to respond to #match: 0)
CSV.parse(str, skip_lines: 0)
Параметр strip

Указывает булево значение, определяющее, удалять ли пробелы из каждого входного поля.

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

CSV::DEFAULT_OPTIONS.fetch(:strip) # => false

Со значением по умолчанию false:

ary = CSV.parse_line(' a , b ')
ary # => [" a ", " b "]

Со значением true:

ary = CSV.parse_line(' a , b ', strip: true)
ary # => ["a", "b"]
Параметр liberal_parsing

Указывает булево значение, определяющее, будет ли CSV пытаться разобрать ввод, не соответствующий RFC 4180, например, двойные кавычки в нецитируемых полях.

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

CSV::DEFAULT_OPTIONS.fetch(:liberal_parsing) # => false

Для примеров в этом разделе:

str = 'is,this "three, or four",fields'

Без liberal_parsing:

# Raises CSV::MalformedCSVError (Illegal quoting in str 1.)
CSV.parse_line(str)

С liberal_parsing:

ary = CSV.parse_line(str, liberal_parsing: true)
ary # => ["is", "this \"three", " or four\"", "fields"]
Параметр nil_value

Указывает объект, который должен быть подставлен для каждого пустого (без текста) поля.

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

CSV::DEFAULT_OPTIONS.fetch(:nil_value) # => nil

Со значением по умолчанию, nil:

CSV.parse_line('a,,b,,c') # => ["a", nil, "b", nil, "c"]

С другим объектом:

CSV.parse_line('a,,b,,c', nil_value: 0) # => ["a", 0, "b", 0, "c"]
Параметр empty_value

Указывает объект, который должен быть подставлен для каждого поля, содержащего пустую строку.

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

CSV::DEFAULT_OPTIONS.fetch(:empty_value) # => "" (empty string)

Со значением по умолчанию, "":

CSV.parse_line('a,"",b,"",c') # => ["a", "", "b", "", "c"]

С другим объектом:

CSV.parse_line('a,"",b,"",c', empty_value: 'x') # => ["a", "x", "b", "x", "c"]

Параметры для генерации

Параметры для генерации, описанные подробно ниже, включают:

  • row_sep: Указывает разделитель строк; используется для разграничения строк.

  • col_sep: Указывает разделитель столбцов; используется для разграничения полей.

  • quote_char: Указывает символ кавычек; используется для кавычек полей.

  • write_headers: Указывает, нужно ли записывать заголовки.

  • force_quotes: Указывает, нужно ли заключать каждое выходное поле в кавычки.

  • quote_empty: Указывает, нужно ли заключать каждое пустое выходное поле в кавычки.

  • write_converters: Указывает используемые преобразователи полей для записи.

  • write_nil_value: Указывает объект, который нужно заменить в каждом поле со значением nil.

  • write_empty_value: Указывает объект, который нужно заменить в каждом пустом поле.

Параметр row_sep

Указывает разделитель строк, строку или символ :auto (см. ниже), используемый для парсинга и генерации.

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

CSV::DEFAULT_OPTIONS.fetch(:row_sep) # => :auto

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

Использование "\n":

row_sep = "\n"
str = CSV.generate(row_sep: row_sep) do |csv|
  csv << [:foo, 0]
  csv << [:bar, 1]
  csv << [:baz, 2]
end
str # => "foo,0\nbar,1\nbaz,2\n"
ary = CSV.parse(str)
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]

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

row_sep = '|'
str = CSV.generate(row_sep: row_sep) do |csv|
  csv << [:foo, 0]
  csv << [:bar, 1]
  csv << [:baz, 2]
end
str # => "foo,0|bar,1|baz,2|"
ary = CSV.parse(str, row_sep: row_sep)
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]

Использование -- (два дефиса):

row_sep = '--'
str = CSV.generate(row_sep: row_sep) do |csv|
  csv << [:foo, 0]
  csv << [:bar, 1]
  csv << [:baz, 2]
end
str # => "foo,0--bar,1--baz,2--"
ary = CSV.parse(str, row_sep: row_sep)
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]

Использование '' (пустая строка):

row_sep = ''
str = CSV.generate(row_sep: row_sep) do |csv|
  csv << [:foo, 0]
  csv << [:bar, 1]
  csv << [:baz, 2]
end
str # => "foo,0bar,1baz,2"
ary = CSV.parse(str, row_sep: row_sep)
ary # => [["foo", "0bar", "1baz", "2"]]

Когда row_sep является символом :auto (по умолчанию), при генерации используется "\n" в качестве разделителя строк:

str = CSV.generate do |csv|
  csv << [:foo, 0]
  csv << [:bar, 1]
  csv << [:baz, 2]
end
str # => "foo,0\nbar,1\nbaz,2\n"

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

Автоматическое определение считывает данные вперед, ища последовательность \r\n, \n или \r. Последовательность будет выбрана даже если она встречается в цитируемом поле, предполагая, что у вас там будут те же самые окончания строк.

Пример:

str = CSV.generate do |csv|
  csv << [:foo, 0]
  csv << [:bar, 1]
  csv << [:baz, 2]
end
str # => "foo,0\nbar,1\nbaz,2\n"
ary = CSV.parse(str)
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]

По умолчанию используется $INPUT_RECORD_SEPARATOR ($/) если выполняется одно из следующих условий:

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

  • Данные являются ARGF, STDIN, STDOUT или STDERR.

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

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

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

row_sep = BasicObject.new
# Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
CSV.generate(ary, row_sep: row_sep)
# Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
CSV.parse(str, row_sep: row_sep)
Параметр col_sep

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

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

CSV::DEFAULT_OPTIONS.fetch(:col_sep) # => "," (comma)

Использование значения по умолчанию (запятая):

str = CSV.generate do |csv|
  csv << [:foo, 0]
  csv << [:bar, 1]
  csv << [:baz, 2]
end
str # => "foo,0\nbar,1\nbaz,2\n"
ary = CSV.parse(str)
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]

Использование : (двоеточие):

col_sep = ':'
str = CSV.generate(col_sep: col_sep) do |csv|
  csv << [:foo, 0]
  csv << [:bar, 1]
  csv << [:baz, 2]
end
str # => "foo:0\nbar:1\nbaz:2\n"
ary = CSV.parse(str, col_sep: col_sep)
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]

Использование :: (два двоеточия):

col_sep = '::'
str = CSV.generate(col_sep: col_sep) do |csv|
  csv << [:foo, 0]
  csv << [:bar, 1]
  csv << [:baz, 2]
end
str # => "foo::0\nbar::1\nbaz::2\n"
ary = CSV.parse(str, col_sep: col_sep)
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]

Использование '' (пустая строка):

col_sep = ''
str = CSV.generate(col_sep: col_sep) do |csv|
  csv << [:foo, 0]
  csv << [:bar, 1]
  csv << [:baz, 2]
end
str # => "foo0\nbar1\nbaz2\n"

Вызывает исключение при парсинге с пустой строкой:

col_sep = ''
# Raises ArgumentError (:col_sep must be 1 or more characters: "")
CSV.parse("foo0\nbar1\nbaz2\n", col_sep: col_sep)

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

col_sep = BasicObject.new
# Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
CSV.generate(line, col_sep: col_sep)
# Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
CSV.parse(str, col_sep: col_sep)
Параметр quote_char

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

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

CSV::DEFAULT_OPTIONS.fetch(:quote_char) # => "\"" (double quote)

Это полезно для приложения, которое неправильно использует ' (одинарная кавычка) для цитирования полей вместо правильной " (двойная кавычка).

Использование значения по умолчанию (двойная кавычка):

str = CSV.generate do |csv|
  csv << ['foo', 0]
  csv << ["'bar'", 1]
  csv << ['"baz"', 2]
end
str # => "foo,0\n'bar',1\n\"\"\"baz\"\"\",2\n"
ary = CSV.parse(str)
ary # => [["foo", "0"], ["'bar'", "1"], ["\"baz\"", "2"]]

Использование ' (одинарная кавычка):

quote_char = "'"
str = CSV.generate(quote_char: quote_char) do |csv|
  csv << ['foo', 0]
  csv << ["'bar'", 1]
  csv << ['"baz"', 2]
end
str # => "foo,0\n'''bar''',1\n\"baz\",2\n"
ary = CSV.parse(str, quote_char: quote_char)
ary # => [["foo", "0"], ["'bar'", "1"], ["\"baz\"", "2"]]

Вызывает исключение, если длина строки больше 1:

# Raises ArgumentError (:quote_char has to be nil or a single character String)
CSV.new('', quote_char: 'xx')

Вызывает исключение, если значение не является строкой:

# Raises ArgumentError (:quote_char has to be nil or a single character String)
CSV.new('', quote_char: :foo)
Параметр write_headers

Указывает булево значение, определяющее, включать ли строку заголовков в выходные данные; игнорируется, если заголовки отсутствуют.

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

CSV::DEFAULT_OPTIONS.fetch(:write_headers) # => nil

Без write_headers:

file_path = 't.csv'
CSV.open(file_path,'w',
    :headers => ['Name','Value']
  ) do |csv|
    csv << ['foo', '0']
end
CSV.open(file_path) do |csv|
  csv.shift
end # => ["foo", "0"]

С write_headers:

CSV.open(file_path,'w',
    :write_headers=> true,
    :headers => ['Name','Value']
  ) do |csv|
    csv << ['foo', '0']
end
CSV.open(file_path) do |csv|
  csv.shift
end # => ["Name", "Value"]
Параметр force_quotes

Указывает булево значение, определяющее, нужно ли заключать каждое выходное поле в двойные кавычки.

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

CSV::DEFAULT_OPTIONS.fetch(:force_quotes) # => false

Для примеров в этом разделе:

ary = ['foo', 0, nil]

Использование значения по умолчанию, false:

str = CSV.generate_line(ary)
str # => "foo,0,\n"

Использование true:

str = CSV.generate_line(ary, force_quotes: true)
str # => "\"foo\",\"0\",\"\"\n"
Параметр quote_empty

Указывает булево значение, определяющее, нужно ли заключать пустое значение в двойные кавычки.

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

CSV::DEFAULT_OPTIONS.fetch(:quote_empty) # => true

Со значением по умолчанию true:

CSV.generate_line(['"', ""]) # => "\"\"\"\",\"\"\n"

Со значением false:

CSV.generate_line(['"', ""], quote_empty: false) # => "\"\"\"\",\n"
Параметр write_converters

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

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

CSV::DEFAULT_OPTIONS.fetch(:write_converters) # => nil

Без преобразователя записи:

str = CSV.generate_line(["\na\n", "\tb\t", " c "])
str # => "\"\na\n\",\tb\t, c \n"

С преобразователем записи:

strip_converter = proc {|field| field.strip }
str = CSV.generate_line(["\na\n", "\tb\t", " c "], write_converters: strip_converter)
str # => "a,b,c\n"

С двумя преобразователями записи (вызываемыми в порядке):

upcase_converter = proc {|field| field.upcase }
downcase_converter = proc {|field| field.downcase }
write_converters = [upcase_converter, downcase_converter]
str = CSV.generate_line(['a', 'b', 'c'], write_converters: write_converters)
str # => "a,b,c\n"

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

Вызывает исключение, если преобразователь возвращает значение, которое не является nil или не может быть преобразовано в строку:

bad_converter = proc {|field| BasicObject.new }
# Raises NoMethodError (undefined method `is_a?' for #<BasicObject:>)
CSV.generate_line(['a', 'b', 'c'], write_converters: bad_converter)#
Параметр write_nil_value

Указывает объект, который будет заменён на каждое поле со значением nil.

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

CSV::DEFAULT_OPTIONS.fetch(:write_nil_value) # => nil

Без параметра:

str = CSV.generate_line(['a', nil, 'c', nil])
str # => "a,,c,\n"

С параметром:

str = CSV.generate_line(['a', nil, 'c', nil], write_nil_value: "x")
str # => "a,x,c,x\n"
Параметр write_empty_value

Указывает объект, который будет заменён на каждое поле со значением пустой строки.

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

CSV::DEFAULT_OPTIONS.fetch(:write_empty_value) # => ""

Без параметра:

str = CSV.generate_line(['a', '', 'c', ''])
str # => "a,\"\",c,\"\"\n"

С параметром:

str = CSV.generate_line(['a', '', 'c', ''], write_empty_value: "x")
str # => "a,x,c,x\n"

CSV с заголовками

CSV позволяет указывать имена столбцов файла CSV, либо они берутся из данных, либо задаются отдельно. Если заголовки заданы, методы чтения возвращают экземпляр CSV::Table, состоящий из CSV::Row.

# Headers are part of data
data = CSV.parse(<<~ROWS, headers: true)
  Name,Department,Salary
  Bob,Engineering,1000
  Jane,Sales,2000
  John,Management,5000
ROWS

data.class      #=> CSV::Table
data.first      #=> #<CSV::Row "Name":"Bob" "Department":"Engineering" "Salary":"1000">
data.first.to_h #=> {"Name"=>"Bob", "Department"=>"Engineering", "Salary"=>"1000"}

# Headers provided by developer
data = CSV.parse('Bob,Engineering,1000', headers: %i[name department salary])
data.first      #=> #<CSV::Row name:"Bob" department:"Engineering" salary:"1000">

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

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

  • См. Преобразователи полей.

  • См. Преобразователи заголовков.

Также по умолчанию каждое значение, которое нужно записать при генерации, записывается «как есть». Вы можете использовать преобразователь записи для изменения значений перед записью.

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

Указание преобразователей

Вы можете указать преобразователи для парсинга или генерации в аргументе options для различных методов CSV:

  • Параметр converters для преобразования анализируемых значений полей.

  • Параметр header_converters для преобразования анализируемых значений заголовков.

  • Параметр write_converters для преобразования значений, которые будут записаны (сгенерированы).

Существуют три формы указания преобразователей:

  • Процедура преобразования: выполняемый код для преобразования.

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

  • Список преобразователей: массив процедур преобразования, имен преобразователей и списков преобразователей.

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

Эта процедура преобразования, strip_converter, принимает значение field и возвращает field.strip:

strip_converter = proc {|field| field.strip }

В этом вызове CSV.parse, ключевой аргумент converters: string_converter указывает, что:

  • Процедура string_converter будет вызываться для каждого анализируемого поля.

  • Возвращаемое значение преобразователя заменит значение field.

Пример:

string = " foo , 0 \n bar , 1 \n baz , 2 \n"
array = CSV.parse(string, converters: strip_converter)
array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]

Процедура преобразования может принимать второй аргумент, field_info, который содержит данные о поле. Этот измененный strip_converter отображает свои аргументы:

strip_converter = proc do |field, field_info|
  p [field, field_info]
  field.strip
end
string = " foo , 0 \n bar , 1 \n baz , 2 \n"
array = CSV.parse(string, converters: strip_converter)
array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]

Вывод:

[" foo ", #<struct CSV::FieldInfo index=0, line=1, header=nil>]
[" 0 ", #<struct CSV::FieldInfo index=1, line=1, header=nil>]
[" bar ", #<struct CSV::FieldInfo index=0, line=2, header=nil>]
[" 1 ", #<struct CSV::FieldInfo index=1, line=2, header=nil>]
[" baz ", #<struct CSV::FieldInfo index=0, line=3, header=nil>]
[" 2 ", #<struct CSV::FieldInfo index=1, line=3, header=nil>]

Каждый объект CSV::FieldInfo отображает:

  • Индекс поля, отсчитываемый с 0.

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

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

Сохраненные преобразователи

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

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

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

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

  • :date: преобразует каждую строковую дату в дату.

  • :date_time: преобразует каждую строковую дату-время в дату-время.

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

strip_converter = proc {|field| field.strip }
CSV::Converters[:strip] = strip_converter

Затем метод парсинга может сослаться на преобразователь по его имени, :strip:

string = " foo , 0 \n bar , 1 \n baz , 2 \n"
array = CSV.parse(string, converters: :strip)
array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]

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

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

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

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

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

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

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

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

  • Имена сохранённых преобразователей.

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

Примеры:

numeric_converters = [:integer, :float]
date_converters = [:date, :date_time]
[numeric_converters, strip_converter]
[strip_converter, date_converters, :float]

Как процедура преобразования, список преобразователей может быть именован и сохранён в CSV::Converters или CSV::HeaderConverters:

CSV::Converters[:custom] = [strip_converter, date_converters, :float]
CSV::HeaderConverters[:custom] = [:downcase, :symbol]

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

CSV::Converters[:numeric] # => [:integer, :float]
CSV::Converters[:all] # => [:date_time, :numeric]

Преобразователи полей

Без преобразования все проанализированные поля во всех строках становятся строками:

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

Когда вы указываете преобразователь поля, каждое проанализированное поле передаётся преобразователю; его возвращаемое значение становится сохранённым значением для поля. Преобразователь может, например, преобразовать целое число, вставленное в строку, в истинное целое число. (Фактически, именно это делает встроенный преобразователь полей :integer.)

Существует три способа использования преобразователей полей.

  • Использование опции converters с методом анализа:

    ary = CSV.parse(string, converters: :integer)
    ary # => [0, 1, 2] # => [["foo", 0], ["bar", 1], ["baz", 2]]
    
  • Использование опции converters с новым экземпляром CSV:

    csv = CSV.new(string, converters: :integer)
    # Field converters in effect:
    csv.converters # => [:integer]
    csv.read # => [["foo", 0], ["bar", 1], ["baz", 2]]
    
  • Использование метода convert для добавления преобразователя поля к экземпляру CSV:

    csv = CSV.new(string)
    # Add a converter.
    csv.convert(:integer)
    csv.converters # => [:integer]
    csv.read # => [["foo", 0], ["bar", 1], ["baz", 2]]
    

Установка преобразователя поля не влияет на уже прочитанные строки:

csv = CSV.new(string)
csv.shift # => ["foo", "0"]
# Add a converter.
csv.convert(:integer)
csv.converters # => [:integer]
csv.read # => [["bar", 1], ["baz", 2]]

Существуют дополнительные встроенные преобразователи, и также поддерживаются пользовательские преобразователи.

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

Встроенные преобразователи полей находятся в хэше CSV::Converters:

  • Каждый ключ — это имя преобразователя поля.

  • Каждое значение — это одно из:

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

    • Массив имён преобразователей поля.

Вывод:

CSV::Converters.each_pair do |name, value|
  if value.kind_of?(Proc)
    p [name, value.class]
  else
    p [name, value]
  end
end

Выход:

[:integer, Proc]
[:float, Proc]
[:numeric, [:integer, :float]]
[:date, Proc]
[:date_time, Proc]
[:all, [:date_time, :numeric]]

Каждый из этих преобразователей транскодирует значения в UTF-8 перед выполнением преобразования. Если значение не может быть транскодировано в UTF-8, преобразование завершится неудачей, а значение останется не преобразованным.

Преобразователь :integer преобразует каждое поле, которое принимает Integer():

data = '0,1,2,x'
# Without the converter
csv = CSV.parse_line(data)
csv # => ["0", "1", "2", "x"]
# With the converter
csv = CSV.parse_line(data, converters: :integer)
csv # => [0, 1, 2, "x"]

Преобразователь :float преобразует каждое поле, которое принимает Float():

data = '1.0,3.14159,x'
# Without the converter
csv = CSV.parse_line(data)
csv # => ["1.0", "3.14159", "x"]
# With the converter
csv = CSV.parse_line(data, converters: :float)
csv # => [1.0, 3.14159, "x"]

Преобразователь :numeric преобразует с использованием как :integer, так и :float.

Преобразователь :date преобразует каждое поле, которое принимает Date::parse:

data = '2001-02-03,x'
# Without the converter
csv = CSV.parse_line(data)
csv # => ["2001-02-03", "x"]
# With the converter
csv = CSV.parse_line(data, converters: :date)
csv # => [#<Date: 2001-02-03 ((2451944j,0s,0n),+0s,2299161j)>, "x"]

Преобразователь :date_time преобразует каждое поле, которое принимает DateTime::parse:

data = '2020-05-07T14:59:00-05:00,x'
# Without the converter
csv = CSV.parse_line(data)
csv # => ["2020-05-07T14:59:00-05:00", "x"]
# With the converter
csv = CSV.parse_line(data, converters: :date_time)
csv # => [#<DateTime: 2020-05-07T14:59:00-05:00 ((2458977j,71940s,0n),-18000s,2299161j)>, "x"]

Преобразователь :numeric преобразует с использованием как :date_time, так и :numeric.

Как показано выше, метод convert добавляет преобразователи к экземпляру CSV, а метод converters возвращает массив действующих преобразователей:

csv = CSV.new('0,1,2')
csv.converters # => []
csv.convert(:integer)
csv.converters # => [:integer]
csv.convert(:date)
csv.converters # => [:integer, :date]
Пользовательские преобразователи полей

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

strip_converter = proc {|field| field.strip }
string = " foo , 0 \n bar , 1 \n baz , 2 \n"
array = CSV.parse(string, converters: strip_converter)
array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]

Вы можете зарегистрировать преобразователь в хэше Converters, что позволяет ссылаться на него по имени:

CSV::Converters[:strip] = strip_converter
string = " foo , 0 \n bar , 1 \n baz , 2 \n"
array = CSV.parse(string, converters: :strip)
array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]

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

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

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

  • Опция header_converters с методом анализа singleton:

    string = "Name,Count\nFoo,0\n,Bar,1\nBaz,2"
    tbl = CSV.parse(string, headers: true, header_converters: :downcase)
    tbl.class # => CSV::Table
    tbl.headers # => ["name", "count"]
    
  • Опция header_converters с новым экземпляром CSV:

    csv = CSV.new(string, header_converters: :downcase)
    # Header converters in effect:
    csv.header_converters # => [:downcase]
    tbl = CSV.parse(string, headers: true)
    tbl.headers # => ["Name", "Count"]
    
  • 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 анализатор понимает m17n. Анализатор работает в кодировке Encoding объекта IO или String, который читается или записывается. Ваши данные никогда не транскодируются (если вы не попросите Ruby их транскодировать), и они буквально будут анализироваться в Encoding, в которой они находятся. Таким образом, CSV вернёт массивы или строки строк в Encoding ваших данных. Это достигается транскодированием самого анализатора в вашу Encoding.

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

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

В любом случае, практический аспект этого прост: убедитесь, что объекты IO и String, переданные в CSV, имеют установленную соответствующую Encoding, и всё должно работать. CSV методы, которые позволяют вам открыть объекты IO (CSV::foreach(), CSV::open(), CSV::read() и CSV::readlines()) позволяют вам указать Encoding.

Одно небольшое исключение возникает при создании CSV в String с Encoding, несовместимой с ASCII. Для CSV не существует данных, которые можно было бы использовать для подготовки, и поэтому вам, скорее всего, придётся вручную указать желаемую Encoding в большинстве таких случаев. Тем не менее, при использовании CSV::generate_line() или Array#to_csv() он попытается угадать, используя поля в строке вывода.

Я стараюсь указывать любые другие Encoding проблемы в документации методов по мере их возникновения.

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

Константы

ConverterEncoding

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

Converters

Хэш, содержащий имена и Procs для встроенных преобразователей полей. См. Встроенные преобразователи полей.

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

DEFAULT_OPTIONS

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

DateMatcher

A Regexp используемый для поиска и преобразования некоторых распространенных Date форматов.

DateTimeMatcher

A Regexp используемый для поиска и преобразования некоторых распространенных DateTime форматов.

FieldInfo

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

index

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

line

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

header

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

HeaderConverters

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

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

VERSION

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

Атрибуты

encoding[R]

:call-seq:

csv.encoding -> endcoding

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

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

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

filter(**options) {|row| ... } Показать исходный код
filter(in_string, **options) {|row| ... }
filter(in_io, **options) {|row| ... }
filter(in_string, out_string, **options) {|row| ... }
filter(in_string, out_io, **options) {|row| ... }
filter(in_io, out_string, **options) {|row| ... }
filter(in_io, out_io, **options) {|row| ... }
# File lib/csv.rb, line 1064
def filter(input=nil, output=nil, **options)
  # parse options for input, output, or both
  in_options, out_options = Hash.new, {row_sep: InputRecordSeparator.value}
  options.each do |key, value|
    case key.to_s
    when /\Ain(?:put)?_(.+)\Z/
      in_options[$1.to_sym] = value
    when /\Aout(?:put)?_(.+)\Z/
      out_options[$1.to_sym] = value
    else
      in_options[key]  = value
      out_options[key] = value
    end
  end

  # build input and output wrappers
  input  = new(input  || ARGF, **in_options)
  output = new(output || $stdout, **out_options)

  # process headers
  need_manual_header_output =
    (in_options[:headers] and
     out_options[:headers] == true and
     out_options[:write_headers])
  if need_manual_header_output
    first_row = input.shift
    if first_row
      if first_row.is_a?(Row)
        headers = first_row.headers
        yield headers
        output << headers
      end
      yield first_row
      output << first_row
    end
  end

  # read, yield, write
  input.each do |row|
    yield row
    output << row
  end
end

Считывает CSV-входные данные и записывает CSV-выходные данные.

Для каждой входной строки:

  • Преобразует данные в:

    • Объект CSV::Row, если используются заголовки.

    • Массив массивов в противном случае.

  • Вызывает блок с этим объектом.

  • Добавляет возвращаемое значение блока в выходные данные.

Аргументы:

  • Источник CSV:

    • Аргумент in_string, если задан, должен быть объектом String; он будет помещён в новый объект StringIO, размещённый в начале.

    • Аргумент in_io, если задан, должен быть объектом IO, открытым для чтения; по завершении, объект IO будет закрыт.

    • Если ни in_string ни in_io не заданы, входной поток по умолчанию — ARGF.

  • CSV-выходные данные:

    • Аргумент out_string, если задан, должен быть объектом String; он будет помещён в новый объект StringIO, размещённый в начале.

    • Аргумент out_io, если задан, должен быть объектом IO, открытым для записи; по завершении, объект IO будет закрыт.

    • Если ни out_string ни out_io не заданы, выходной поток по умолчанию — $stdout.

  • Аргумент options должен быть ключевыми аргументами.

    • Каждое имя аргумента, которое начинается с in_ или input_, лишается префикса и рассматривается как опция для разбора входных данных. Опция input_row_sep по умолчанию равна $INPUT_RECORD_SEPARATOR.

    • Каждое имя аргумента, которое начинается с out_ или output_ лишается префикса и рассматривается как опция для генерации выходных данных. Опция output_row_sep по умолчанию равна $INPUT_RECORD_SEPARATOR.

    • Каждый аргумент, не имеющий указанных выше префиксов, рассматривается как опция для разбора входных данных и генерации выходных данных.

    • См. Опции для разбора и Опции для генерации.

Пример:

in_string = "foo,0\nbar,1\nbaz,2\n"
out_string = ''
CSV.filter(in_string, out_string) do |row|
  row[0] = row[0].upcase
  row[1] *= 4
end
out_string # => "FOO,0000\nBAR,1111\nBAZ,2222\n"
foreach(path, mode='r', **options) {|row| ... ) Показать исходный код
foreach(io, mode='r', **options {|row| ... )
foreach(path, mode='r', headers: ..., **options) {|row| ... )
foreach(io, mode='r', headers: ..., **options {|row| ... )
foreach(path, mode='r', **options) → new_enumerator
foreach(io, mode='r', **options → new_enumerator
# File lib/csv.rb, line 1215
def foreach(path, mode="r", **options, &block)
  return to_enum(__method__, path, mode, **options) unless block_given?
  open(path, mode, **options) do |csv|
    csv.each(&block)
  end
end

Вызывает блок с каждой строкой, считанной из источника path или io.

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

  • Аргумент io должен быть объектом IO, который:

    • Открыт для чтения; по завершении, объект IO будет закрыт.

    • Размещён в начале. Чтобы разместить в конце для добавления, используйте метод CSV.generate. Для любого другого позиционирования передайте предварительно заданный объект StringIO.

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

  • Аргументы mode должны быть ключевыми опциями. См. Опции для разбора.

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

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

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

Без опции headers

Без опции headers, каждая строка возвращается как объект Array.

Эти примеры предполагают предшествующее выполнение:

string = "foo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)

Чтение строк из файла по адресу path:

CSV.foreach(path) {|row| p row }

Вывод:

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

Чтение строк из объекта IO:

File.open(path) do |file|
  CSV.foreach(file) {|row| p row }
end

Вывод:

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

Возвращает новый Enumerator, если блок не задан:

CSV.foreach(path) # => #<Enumerator: CSV:foreach("t.csv", "r")>
CSV.foreach(File.open(path)) # => #<Enumerator: CSV:foreach(#<File:t.csv>, "r")>

Выводит предупреждение, если кодировка не поддерживается:

CSV.foreach(File.open(path), encoding: 'foo:bar') {|row| }

Вывод:

warning: Unsupported encoding foo ignored
warning: Unsupported encoding bar ignored
С опцией headers

С опцией {option headers}, каждая строка возвращается как объект CSV::Row.

Эти примеры предполагают предшествующее выполнение:

string = "Name,Count\nfoo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)

Чтение строк из файла по адресу path:

CSV.foreach(path, headers: true) {|row| p row }

Вывод:

#<CSV::Row "Name":"foo" "Count":"0">
#<CSV::Row "Name":"bar" "Count":"1">
#<CSV::Row "Name":"baz" "Count":"2">

Чтение строк из объекта IO:

File.open(path) do |file|
  CSV.foreach(file, headers: true) {|row| p row }
end

Вывод:

#<CSV::Row "Name":"foo" "Count":"0">
#<CSV::Row "Name":"bar" "Count":"1">
#<CSV::Row "Name":"baz" "Count":"2">

Выбрасывает исключение, если path является строкой, но не путём к читаемому файлу:

# Raises Errno::ENOENT (No such file or directory @ rb_sysopen - nosuch.csv):
CSV.foreach('nosuch.csv') {|row| }

Выбрасывает исключение, если io является объектом IO, но не открыт для чтения:

io = File.open(path, 'w') {|row| }
# Raises TypeError (no implicit conversion of nil into String):
CSV.foreach(io) {|row| }

Выбрасывает исключение, если mode недействителен:

# Raises ArgumentError (invalid access mode nosuch):
CSV.foreach(path, 'nosuch') {|row| }
generate(csv_string, **options) {|csv| ... } Показать исходный код
generate(**options) {|csv| ... }
# File lib/csv.rb, line 1281
def generate(str=nil, **options)
  encoding = options[:encoding]
  # add a default empty String, if none was given
  if str
    str = StringIO.new(str)
    str.seek(0, IO::SEEK_END)
    str.set_encoding(encoding) if encoding
  else
    str = +""
    str.force_encoding(encoding) if encoding
  end
  csv = new(str, **options) # wrap
  yield csv         # yield for appending
  csv.string        # return final String
end
  • Аргумент csv_string, если задан, должен быть объектом String; по умолчанию — пустая строка.

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

Создаёт новый объект CSV с помощью CSV.new(csv_string, **options); вызывает блок с объектом CSV, который может быть изменён блоком; возвращает строку, сгенерированную из объекта CSV.

Обратите внимание, что переданная строка модифицируется этим методом. Передайте csv_string.dup, если строка должна быть сохранена.

Этот метод имеет одну дополнительную опцию: :encoding, которая устанавливает базу Encoding для вывода, если не указана кодировка str. CSV нуждается в этом подсказке, если вы планируете выводить данные, несовместимые с ASCII.

Добавить строки:

input_string = "foo,0\nbar,1\nbaz,2\n"
output_string = CSV.generate(input_string) do |csv|
  csv << ['bat', 3]
  csv << ['bam', 4]
end
output_string # => "foo,0\nbar,1\nbaz,2\nbat,3\nbam,4\n"
input_string # => "foo,0\nbar,1\nbaz,2\nbat,3\nbam,4\n"
output_string.equal?(input_string) # => true # Same string, modified

Добавить строки в новую строку, сохранив старую строку:

input_string = "foo,0\nbar,1\nbaz,2\n"
output_string = CSV.generate(input_string.dup) do |csv|
  csv << ['bat', 3]
  csv << ['bam', 4]
end
output_string # => "foo,0\nbar,1\nbaz,2\nbat,3\nbam,4\n"
input_string # => "foo,0\nbar,1\nbaz,2\n"
output_string.equal?(input_string) # => false # Different strings

Создать строки из ничего:

output_string = CSV.generate do |csv|
  csv << ['foo', 0]
  csv << ['bar', 1]
  csv << ['baz', 2]
end
output_string # => "foo,0\nbar,1\nbaz,2\n"

Выбрасывает исключение, если csv_string не является объектом String:

# Raises TypeError (no implicit conversion of Integer into String)
CSV.generate(0)
generate_line(ary) Показать исходный код
generate_line(ary, **options)
# File lib/csv.rb, line 1329
def generate_line(row, **options)
  options = {row_sep: InputRecordSeparator.value}.merge(options)
  str = +""
  if options[:encoding]
    str.force_encoding(options[:encoding])
  else
    fallback_encoding = nil
    output_encoding = nil
    row.each do |field|
      next unless field.is_a?(String)
      fallback_encoding ||= field.encoding
      next if field.ascii_only?
      output_encoding = field.encoding
      break
    end
    output_encoding ||= fallback_encoding
    if output_encoding
      str.force_encoding(output_encoding)
    end
  end
  (new(str, **options) << row).string
end

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

Аргумент ary должен быть массивом.

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

  • Опция :row_sep по умолчанию равна "\n"> on Ruby 3.0 or later and <tt>$INPUT_RECORD_SEPARATOR ($/) в противном случае.:

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

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

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

CSV.generate_line(['foo', '0']) # => "foo,0\n"

Выбрасывает исключение, если ary не является массивом:

# Raises NoMethodError (undefined method `find' for :foo:Symbol)
CSV.generate_line(:foo)
instance(string, **options) Показать исходный код
instance(io = $stdout, **options)
instance(string, **options) {|csv| ... }
instance(io = $stdout, **options) {|csv| ... }
# File lib/csv.rb, line 993
def instance(data = $stdout, **options)
  # create a _signature_ for this method call, data object and options
  sig = [data.object_id] +
        options.values_at(*DEFAULT_OPTIONS.keys.sort_by { |sym| sym.to_s })

  # fetch or create the instance for this signature
  @@instances ||= Hash.new
  instance = (@@instances[sig] ||= new(data, **options))

  if block_given?
    yield instance  # run block, if given, returning result
  else
    instance        # or return the instance
  end
end

Создаёт или извлекает кэшированные объекты CSV. Для аргументов и опций см. CSV.new.

Этот API не является Ractor-безопасным.

Без блока возвращает объект CSV.

Первый вызов instance создаёт и кэширует объект CSV:

s0 = 's0'
csv0 = CSV.instance(s0)
csv0.class # => CSV

Последующие вызовы instance с тем же string или io извлекают тот же кэшированный объект:

csv1 = CSV.instance(s0)
csv1.class # => CSV
csv1.equal?(csv0) # => true # Same CSV object

Последующий вызов instance с другим string или io создаёт и кэширует другой объект CSV.

s1 = 's1'
csv2 = CSV.instance(s1)
csv2.equal?(csv0) # => false # Different CSV object

Все кэшированные объекты остаются доступными:

csv3 = CSV.instance(s0)
csv3.equal?(csv0) # true # Same CSV object
csv4 = CSV.instance(s1)
csv4.equal?(csv2) # true # Same CSV object

При передаче блока, вызывается блок с созданным или извлечённым объектом CSV; возвращается значение результата блока:

CSV.instance(s0) {|csv| :foo } # => :foo
new(string) Показать исходный код
new(io)
new(string, **options)
new(io, **options)
# File lib/csv.rb, line 1744
def initialize(data,
               col_sep: ",",
               row_sep: :auto,
               quote_char: '"',
               field_size_limit: nil,
               converters: nil,
               unconverted_fields: nil,
               headers: false,
               return_headers: false,
               write_headers: nil,
               header_converters: nil,
               skip_blanks: false,
               force_quotes: false,
               skip_lines: nil,
               liberal_parsing: false,
               internal_encoding: nil,
               external_encoding: nil,
               encoding: nil,
               nil_value: nil,
               empty_value: "",
               strip: false,
               quote_empty: true,
               write_converters: nil,
               write_nil_value: nil,
               write_empty_value: "")
  raise ArgumentError.new("Cannot parse nil as CSV") if data.nil?

  if data.is_a?(String)
    @io = StringIO.new(data)
    @io.set_encoding(encoding || data.encoding)
  else
    @io = data
  end
  @encoding = determine_encoding(encoding, internal_encoding)

  @base_fields_converter_options = {
    nil_value: nil_value,
    empty_value: empty_value,
  }
  @write_fields_converter_options = {
    nil_value: write_nil_value,
    empty_value: write_empty_value,
  }
  @initial_converters = converters
  @initial_header_converters = header_converters
  @initial_write_converters = write_converters

  @parser_options = {
    column_separator: col_sep,
    row_separator: row_sep,
    quote_character: quote_char,
    field_size_limit: field_size_limit,
    unconverted_fields: unconverted_fields,
    headers: headers,
    return_headers: return_headers,
    skip_blanks: skip_blanks,
    skip_lines: skip_lines,
    liberal_parsing: liberal_parsing,
    encoding: @encoding,
    nil_value: nil_value,
    empty_value: empty_value,
    strip: strip,
  }
  @parser = nil
  @parser_enumerator = nil
  @eof_error = nil

  @writer_options = {
    encoding: @encoding,
    force_encoding: (not encoding.nil?),
    force_quotes: force_quotes,
    headers: headers,
    write_headers: write_headers,
    column_separator: col_sep,
    row_separator: row_sep,
    quote_character: quote_char,
    quote_empty: quote_empty,
  }

  @writer = nil
  writer if @writer_options[:write_headers]
end

Возвращает новый объект CSV, созданный с помощью string или io и указанными options.

  • Аргумент string должен быть объектом String; он будет помещён в новый объект StringIO, установленный в начало.

  • Аргумент io должен быть объектом IO, который:

    • Открыт для чтения; по возвращении объект IO будет закрыт.

    • Установлен в начало. Чтобы установить в конец для добавления, используйте метод CSV.generate. Для других позиций используйте предварительно заданный объект StringIO.

  • Аргумент options: См.:

    • Параметры для парсинга

    • Параметры для генерации

    По соображениям производительности, параметры не могут быть переопределены в объекте CSV, поэтому указанные здесь останутся.

Помимо методов экземпляра CSV, несколько методов IO делегированы. См. Делегированные методы.

Создайте объект CSV из объекта String:

csv = CSV.new('foo,0')
csv # => #<CSV io_type:StringIO encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">

Создайте объект CSV из объекта File:

File.write('t.csv', 'foo,0')
csv = CSV.new(File.open('t.csv'))
csv # => #<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">

Вызывает исключение, если аргумент является nil:

# Raises ArgumentError (Cannot parse nil as CSV):
CSV.new(nil)
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 1424
def open(filename, mode="r", **options)
  # wrap a File opened with the remaining +args+ with no newline
  # decorator
  file_opts = {universal_newline: false}.merge(options)
  options.delete(:invalid)
  options.delete(:undef)
  options.delete(:replace)

  begin
    f = File.open(filename, mode, **file_opts)
  rescue ArgumentError => e
    raise unless /needs binmode/.match?(e.message) and mode == "r"
    mode = "rb"
    file_opts = {encoding: Encoding.default_external}.merge(file_opts)
    retry
  end
  begin
    csv = new(f, **options)
  rescue Exception
    f.close
    raise
  end

  # handle blocks like Ruby's open(), not like the CSV library
  if block_given?
    begin
      yield csv
    ensure
      csv.close
    end
  else
    csv
  end
end

Возможные элементы параметров:

hash form:
  :invalid => nil      # raise error on invalid byte sequence (default)
  :invalid => :replace # replace invalid byte sequence
  :undef => :replace   # replace undefined conversion
  :replace => string   # replacement string ("?" or "\uFFFD" if not specified)
  • Аргумент path, если задан, должен быть путём к файлу.

  • Аргумент io должен быть объектом IO, который:

    • Открыт для чтения; по возвращении объект IO будет закрыт.

    • Установлен в начало. Чтобы установить в конец для добавления, используйте метод CSV.generate. Для других позиций используйте предварительно заданный объект StringIO.

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

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

  • Этот метод необязательно принимает дополнительный параметр :encoding, который можно использовать для указания Encoding данных, считанных из path или io. Необходимо предоставить этот параметр, если данные не в кодировке, указанной в Encoding::default_external. Парсинг будет использовать это для определения способа парсинга данных. Можно указать второй Encoding, чтобы данные были транскодированы при чтении. Например,

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

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

Эти примеры предполагают предыдущее выполнение:

string = "foo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)

Без блока возвращает новый объект CSV.

Создайте объект CSV, используя путь к файлу:

csv = CSV.open(path)
csv # => #<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">

Создайте объект CSV, используя открытый файл:

csv = CSV.open(File.open(path))
csv # => #<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">

С блоком, вызывается блок с созданным объектом CSV; возвращается значение результата блока:

Используя путь к файлу:

csv = CSV.open(path) {|csv| p csv}
csv # => #<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">

Вывод:

#<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">

Используя открытый файл:

csv = CSV.open(File.open(path)) {|csv| p csv}
csv # => #<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">

Вывод:

#<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">

Вызывает исключение, если аргумент не является объектом String или IO:

# Raises TypeError (no implicit conversion of Symbol into String)
CSV.open(:foo)
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 1571
def parse(str, **options, &block)
  csv = new(str, **options)

  return csv.each(&block) if block_given?

  # slurp contents, if no block is given
  begin
    csv.read
  ensure
    csv.close
  end
end

Парсит string или io с использованием указанных options.

  • Аргумент string должен быть объектом String; он будет помещён в новый объект StringIO, установленный в начало.

  • Аргумент io должен быть объектом IO, который:

    • Открыт для чтения; по возвращении объект IO будет закрыт.

    • Установлен в начало. Чтобы установить в конец для добавления, используйте метод CSV.generate. Для других позиций используйте предварительно заданный объект StringIO.

  • Аргумент options: см. Параметры для парсинга

Без опции headers

Случай без опции {опция headers}.

Эти примеры предполагают предыдущее выполнение:

string = "foo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)

Без блока возвращает массив массивов, сформированных из источника.

Парсинг строки:

a_of_a = CSV.parse(string)
a_of_a # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]

Парсинг открытого файла:

a_of_a = File.open(path) do |file|
  CSV.parse(file)
end
a_of_a # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]

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

Парсинг строки:

CSV.parse(string) {|row| p row }

Вывод:

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

Парсинг открытого файла:

File.open(path) do |file|
  CSV.parse(file) {|row| p row }
end

Вывод:

["foo", "0"]
["bar", "1"]
["baz", "2"]
С опцией headers

Случай с опцией {опция headers}.

Эти примеры предполагают предыдущее выполнение:

string = "Name,Count\nfoo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)

Без блока возвращает объект CSV::Table, сформированный из источника.

Парсинг строки:

csv_table = CSV.parse(string, headers: ['Name', 'Count'])
csv_table # => #<CSV::Table mode:col_or_row row_count:5>

Парсинг открытого файла:

csv_table = File.open(path) do |file|
  CSV.parse(file, headers: ['Name', 'Count'])
end
csv_table # => #<CSV::Table mode:col_or_row row_count:4>

С блоком, вызывается блок с каждым проанализированным рядом, который был сформирован в объект CSV::Row:

Парсинг строки:

CSV.parse(string, headers: ['Name', 'Count']) {|row| p row }

Вывод:

# <CSV::Row "Name":"foo" "Count":"0">
# <CSV::Row "Name":"bar" "Count":"1">
# <CSV::Row "Name":"baz" "Count":"2">

Парсинг открытого файла:

File.open(path) do |file|
  CSV.parse(file, headers: ['Name', 'Count']) {|row| p row }
end

Вывод:

# <CSV::Row "Name":"foo" "Count":"0">
# <CSV::Row "Name":"bar" "Count":"1">
# <CSV::Row "Name":"baz" "Count":"2">

Вызывает исключение, если аргумент не является объектом String или IO:

# Raises NoMethodError (undefined method `close' for :foo:Symbol)
CSV.parse(:foo)
END_OF_DOCUMENT_MARKER
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 1644
def parse_line(line, **options)
  new(line, **options).each.first
end

Возвращает данные, полученные при разборе первой строки из string или io с использованием указанных options.

  • Аргумент string должен быть объектом String; он будет помещён в новый объект StringIO, позиционированный в начале.

  • Аргумент io должен быть объектом IO, который:

    • Открыт для чтения; по возвращении объект IO будет закрыт.

    • Позиционирован в начале. Для позиционирования в конце, для добавления, используйте метод CSV.generate. Для любого другого позиционирования, передайте предварительно заданный объект StringIO.

  • Аргумент options: см. Параметры разбора

Без параметра headers

Без параметра headers, возвращает первую строку в виде нового массива.

Эти примеры предполагают предыдущее выполнение:

string = "foo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)

Разбор первой строки из объекта String:

CSV.parse_line(string) # => ["foo", "0"]

Разбор первой строки из объекта File:

File.open(path) do |file|
  CSV.parse_line(file) # => ["foo", "0"]
end # => ["foo", "0"]

Возвращает nil если аргумент пустая строка:

CSV.parse_line('') # => nil
С параметром headers

С параметром {параметр headers}, возвращает первую строку в виде объекта CSV::Row.

Эти примеры предполагают предыдущее выполнение:

string = "Name,Count\nfoo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)

Разбор первой строки из объекта String:

CSV.parse_line(string, headers: true) # => #<CSV::Row "Name":"foo" "Count":"0">

Разбор первой строки из объекта File:

File.open(path) do |file|
  CSV.parse_line(file, headers: true)
end # => #<CSV::Row "Name":"foo" "Count":"0">

Выбрасывает исключение, если аргумент nil:

# Raises ArgumentError (Cannot parse nil as CSV):
CSV.parse_line(nil)
read(source, **options) → array_of_arrays Показать исходный код
read(source, headers: true, **options) → csv_table
# File lib/csv.rb, line 1668
def read(path, **options)
  open(path, **options) { |csv| csv.read }
end

Открывает указанный source с указанными options (см. CSV.open), читает источник (см. CSV#read) и возвращает результат, который будет либо массивом массивов, либо таблицей CSV::Table.

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

string = "foo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)
CSV.read(path) # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]

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

string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)
CSV.read(path, headers: true) # => #<CSV::Table mode:col_or_row row_count:4>
readlines(source, **options) Показать исходный код
# File lib/csv.rb, line 1676
def readlines(path, **options)
  read(path, **options)
end

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

table(source, **options) Показать исходный код
# File lib/csv.rb, line 1695
def table(path, **options)
  default_options = {
    headers:           true,
    converters:        :numeric,
    header_converters: :symbol,
  }
  options = default_options.merge(options)
  read(path, **options)
end

Вызывает CSV.read с source, options, и определёнными значениями по умолчанию:

  • headers: true

  • converters: :numeric

  • header_converters: :symbol

Возвращает объект CSV::Table.

Пример:

string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)
CSV.table(path) # => #<CSV::Table mode:col_or_row row_count:4>

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

csv << row → self Показать исходный код
# File lib/csv.rb, line 2182
def <<(row)
  writer << row
  self
end

Добавляет строку в self.

  • Аргумент row должен быть объектом типа Array или объектом CSV::Row.

  • Поток вывода должен быть открыт для записи.

Добавление массивов:

CSV.generate do |csv|
  csv << ['foo', 0]
  csv << ['bar', 1]
  csv << ['baz', 2]
end # => "foo,0\nbar,1\nbaz,2\n"

Добавление CSV::Rows:

headers = []
CSV.generate do |csv|
  csv << CSV::Row.new(headers, ['foo', 0])
  csv << CSV::Row.new(headers, ['bar', 1])
  csv << CSV::Row.new(headers, ['baz', 2])
end # => "foo,0\nbar,1\nbaz,2\n"

Заголовки в объектах CSV::Row не добавляются:

headers = ['Name', 'Count']
CSV.generate do |csv|
  csv << CSV::Row.new(headers, ['foo', 0])
  csv << CSV::Row.new(headers, ['bar', 1])
  csv << CSV::Row.new(headers, ['baz', 2])
end # => "foo,0\nbar,1\nbaz,2\n"

Вызывает исключение, если row не является массивом или CSV::Row:

CSV.generate do |csv|
  # Raises NoMethodError (undefined method `collect' for :foo:Symbol)
  csv << :foo
end

Вызывает исключение, если поток вывода не открыт для записи:

path = 't.csv'
File.write(path, '')
File.open(path) do |file|
  CSV.open(file) do |csv|
    # Raises IOError (not opened for writing)
    csv << ['foo', 0]
  end
end
Также алиасируется как: add_row, puts
add_row(row)
Псевдоним для: <<
binmode?() Показать исходный код
# File lib/csv.rb, line 2071
def binmode?
  if @io.respond_to?(:binmode?)
    @io.binmode?
  else
    false
  end
end
col_sep → string Показать исходный код
# File lib/csv.rb, line 1833
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 2253
def convert(name = nil, &converter)
  parser_fields_converter.add_converter(name, &converter)
end
  • Без блока устанавливает преобразователь поля (Proc).

  • С блоком определяет и устанавливает пользовательский преобразователь поля.

  • Возвращает массив установленных преобразователей полей.

  • Аргумент converter_name, если задан, должен быть именем существующего преобразователя поля.

См. Преобразователи полей.

Без блока устанавливает преобразователь поля:

csv = CSV.new('')
csv.convert(:integer)
csv.convert(:float)
csv.convert(:date)
csv.converters # => [:integer, :float, :date]

Блок, если задан, вызывается для каждого поля:

  • Аргумент field — значение поля.

  • Аргумент field_info — объект CSV::FieldInfo содержащий детали о поле.

Приведенные примеры предполагают предыдущее выполнение:

string = "foo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)

Пример с блоком:

csv = CSV.open(path)
csv.convert {|field, field_info| p [field, field_info]; field.upcase }
csv.read # => [["FOO", "0"], ["BAR", "1"], ["BAZ", "2"]]

Вывод:

["foo", #<struct CSV::FieldInfo index=0, line=1, header=nil>]
["0", #<struct CSV::FieldInfo index=1, line=1, header=nil>]
["bar", #<struct CSV::FieldInfo index=0, line=2, header=nil>]
["1", #<struct CSV::FieldInfo index=1, line=2, header=nil>]
["baz", #<struct CSV::FieldInfo index=0, line=3, header=nil>]
["2", #<struct CSV::FieldInfo index=1, line=3, header=nil>]

Блок не обязан возвращать объект String:

csv = CSV.open(path)
csv.convert {|field, field_info| field.to_sym }
csv.read # => [[:foo, :"0"], [:bar, :"1"], [:baz, :"2"]]

Если converter_name задан, блок не вызывается:

csv = CSV.open(path)
csv.convert(:integer) {|field, field_info| fail 'Cannot happen' }
csv.read # => [["foo", 0], ["bar", 1], ["baz", 2]]

Вызывает исключение во время парсинга, если converter_name не является именем встроенного преобразователя поля:

csv = CSV.open(path)
csv.convert(:nosuch) => [nil]
# Raises NoMethodError (undefined method `arity' for nil:NilClass)
csv.read
converters → array Показать исходный код
# File lib/csv.rb, line 1892
def converters
  parser_fields_converter.map do |converter|
    name = Converters.rassoc(converter)
    name ? name.first : converter
  end
end

Возвращает массив, содержащий преобразователи полей; см. Преобразователи полей:

csv = CSV.new('')
csv.converters # => []
csv.convert(:integer)
csv.converters # => [:integer]
csv.convert(proc {|x| x.to_s })
csv.converters

Обратите внимание, что вам нужно вызвать +Ractor.make_shareable(CSV::Converters)+ на главном Ractor для использования этого метода.

each → enumerator Показать исходный код
each {|row| ...}
# File lib/csv.rb, line 2364
def each(&block)
  parser_enumerator.each(&block)
end

Вызывает блок для каждой последующей строки. Источник данных должен быть открыт для чтения.

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

string = "foo,0\nbar,1\nbaz,2\n"
csv = CSV.new(string)
csv.each do |row|
  p row
end

Вывод:

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

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

string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
csv = CSV.new(string, headers: true)
csv.each do |row|
  p row
end

Вывод:

<CSV::Row "Name":"foo" "Value":"0">
<CSV::Row "Name":"bar" "Value":"1">
<CSV::Row "Name":"baz" "Value":"2">

Вызывает исключение, если источник не открыт для чтения:

string = "foo,0\nbar,1\nbaz,2\n"
csv = CSV.new(string)
csv.close
# Raises IOError (not opened for reading)
csv.each do |row|
  p row
end
eof()
Псевдоним для: eof?
eof?() Показать исходный код
# File lib/csv.rb, line 2107
def eof?
  return false if @eof_error
  begin
    parser_enumerator.peek
    false
  rescue MalformedCSVError => error
    @eof_error = error
    false
  rescue StopIteration
    true
  end
end
Также алиасируется как: eof
field_size_limit → integer or nil Показать исходный код
# File lib/csv.rb, line 1863
def field_size_limit
  parser.field_size_limit
end

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

CSV.new('').field_size_limit # => nil
flock(*args) Показать исходный код
# File lib/csv.rb, line 2079
def flock(*args)
  raise NotImplementedError unless @io.respond_to?(:flock)
  @io.flock(*args)
end
force_quotes? → true or false Показать исходный код
# File lib/csv.rb, line 1982
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 2319
def header_convert(name = nil, &converter)
  header_fields_converter.add_converter(name, &converter)
end

Блок не обязан возвращать объект String:

csv = CSV.open(path, headers: true)
csv.header_convert {|header, field_info| header.to_sym }
table = csv.read
table.headers # => [:Name, :Value]

Если converter_name задан, блок не вызывается:

csv = CSV.open(path, headers: true)
csv.header_convert(:downcase) {|header, field_info| fail 'Cannot happen' }
table = csv.read
table.headers # => ["name", "value"]

Вызывает исключение во время парсинга, если converter_name не является именем встроенного преобразователя поля:

csv = CSV.open(path, headers: true)
csv.header_convert(:nosuch)
# Raises NoMethodError (undefined method `arity' for nil:NilClass)
csv.read
header_converters → array Показать исходный код
# File lib/csv.rb, line 1958
def header_converters
  header_fields_converter.map do |converter|
    name = HeaderConverters.rassoc(converter)
    name ? name.first : converter
  end
end

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

CSV.new('').header_converters # => []

Обратите внимание, что вам нужно вызвать +Ractor.make_shareable(CSV::HeaderConverters)+ на главном Ractor для использования этого метода.

header_row? → true or false Показать исходный код
# File lib/csv.rb, line 2435
def header_row?
  parser.header_row?
end

Возвращает true если следующая считываемая строка — строка заголовков; false в противном случае.

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

string = "foo,0\nbar,1\nbaz,2\n"
csv = CSV.new(string)
csv.header_row? # => false

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

string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
csv = CSV.new(string, headers: true)
csv.header_row? # => true
csv.shift # => #<CSV::Row "Name":"foo" "Value":"0">
csv.header_row? # => false

Вызывает исключение, если источник не открыт для чтения:

string = "foo,0\nbar,1\nbaz,2\n"
csv = CSV.new(string)
csv.close
# Raises IOError (not opened for reading)
csv.header_row?
headers → object Показать исходный код
# File lib/csv.rb, line 1916
def headers
  if @writer
    @writer.headers
  else
    parsed_headers = parser.headers
    return parsed_headers if parsed_headers
    raw_headers = @parser_options[:headers]
    raw_headers = nil if raw_headers == false
    raw_headers
  end
end

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

CSV.new('').headers # => nil
inspect → string Показать исходный код
# File lib/csv.rb, line 2494
def inspect
  str = ["#<", self.class.to_s, " io_type:"]
  # show type of wrapped IO
  if    @io == $stdout then str << "$stdout"
  elsif @io == $stdin  then str << "$stdin"
  elsif @io == $stderr then str << "$stderr"
  else                      str << @io.class.to_s
  end
  # show IO.path(), if available
  if @io.respond_to?(:path) and (p = @io.path)
    str << " io_path:" << p.inspect
  end
  # show encoding
  str << " encoding:" << @encoding.name
  # show other attributes
  ["lineno", "col_sep", "row_sep", "quote_char"].each do |attr_name|
    if a = __send__(attr_name)
      str << " " << attr_name << ":" << a.inspect
    end
  end
  ["skip_blanks", "liberal_parsing"].each do |attr_name|
    if a = __send__("#{attr_name}?")
      str << " " << attr_name << ":" << a.inspect
    end
  end
  _headers = headers
  str << " headers:" << _headers.inspect if _headers
  str << ">"
  begin
    str.join('')
  rescue  # any encoding error
    str.map do |s|
      e = Encoding::Converter.asciicompat_encoding(s.encoding)
      e ? s.encode(e) : s.force_encoding("ASCII-8BIT")
    end.join('')
  end
end

Возвращает строку, отображающую определённые свойства self:

string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
csv = CSV.new(string, headers: true)
s = csv.inspect
s # => "#<CSV io_type:StringIO encoding:UTF-8 lineno:0 col_sep:\",\" row_sep:\"\\n\" quote_char:\"\\\"\" headers:true>"
ioctl(*args) Показать исходный код
# File lib/csv.rb, line 2084
def ioctl(*args)
  raise NotImplementedError unless @io.respond_to?(:ioctl)
  @io.ioctl(*args)
end
END_OF_DOCUMENT_MARKER
liberal_parsing? → true or false Показать исходный код
# File lib/csv.rb, line 1992
def liberal_parsing?
  parser.liberal_parsing?
end

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

CSV.new('').liberal_parsing? # => false
line → массив Показать исходный код
# File lib/csv.rb, line 2057
def line
  parser.line
end

Возвращает самую последнюю прочитанную строку:

string = "foo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)
CSV.open(path) do |csv|
  csv.each do |row|
    p [csv.lineno, csv.line]
  end
end

Вывод:

[1, "foo,0\n"]
[2, "bar,1\n"]
[3, "baz,2\n"]
line_no → целое число Показать исходный код
# File lib/csv.rb, line 2033
def lineno
  if @writer
    @writer.lineno
  else
    parser.lineno
  end
end

Возвращает количество проанализированных или сгенерированных строк.

Разбор:

string = "foo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)
CSV.open(path) do |csv|
  csv.each do |row|
    p [csv.lineno, row]
  end
end

Вывод:

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

Генерация:

CSV.generate do |csv|
  p csv.lineno; csv << ['foo', 0]
  p csv.lineno; csv << ['bar', 1]
  p csv.lineno; csv << ['baz', 2]
end

Вывод:

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

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

CSV.new('').quote_char # => "\""
read → массив или csv_table Показать исходный код
# File lib/csv.rb, line 2399
def read
  rows = to_a
  if parser.use_headers?
    Table.new(rows, headers: parser.headers)
  else
    rows
  end
end

Формирует оставшиеся строки из self в:

  • Объект CSV::Table, если используются заголовки.

  • Массив массивов в противном случае.

Источник данных должен быть открыт для чтения.

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

string = "foo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)
csv = CSV.open(path)
csv.read # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]

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

string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)
csv = CSV.open(path, headers: true)
csv.read # => #<CSV::Table mode:col_or_row row_count:4>

Вызывает исключение, если источник не открыт для чтения:

string = "foo,0\nbar,1\nbaz,2\n"
csv = CSV.new(string)
csv.close
# Raises IOError (not opened for reading)
csv.read
Также псевдоним для: readlines
readline()
Псевдоним для: shift
readlines()
Псевдоним для: read
return_headers? → true or false Показать исходный код
# File lib/csv.rb, line 1934
def return_headers?
  parser.return_headers?
end

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

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

Перематывает базовый объект IO и сбрасывает счётчик строк CSV.

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

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

CSV.new('').row_sep # => "\n"
shift → массив, csv_row или nil Показать исходный код
# File lib/csv.rb, line 2472
def shift
  if @eof_error
    eof_error, @eof_error = @eof_error, nil
    raise eof_error
  end
  begin
    parser_enumerator.next
  rescue StopIteration
    nil
  end
end

Возвращает следующую строку данных как:

  • Массив, если заголовки не используются.

  • Объект CSV::Row, если заголовки используются.

Источник данных должен быть открыт для чтения.

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

string = "foo,0\nbar,1\nbaz,2\n"
csv = CSV.new(string)
csv.shift # => ["foo", "0"]
csv.shift # => ["bar", "1"]
csv.shift # => ["baz", "2"]
csv.shift # => nil

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

string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
csv = CSV.new(string, headers: true)
csv.shift # => #<CSV::Row "Name":"foo" "Value":"0">
csv.shift # => #<CSV::Row "Name":"bar" "Value":"1">
csv.shift # => #<CSV::Row "Name":"baz" "Value":"2">
csv.shift # => nil

Вызывает исключение, если источник не открыт для чтения:

string = "foo,0\nbar,1\nbaz,2\n"
csv = CSV.new(string)
csv.close
# Raises IOError (not opened for reading)
csv.shift
Также псевдоним для: gets, readline
skip_blanks? → true or false Показать исходный код
# File lib/csv.rb, line 1971
def skip_blanks?
  parser.skip_blanks?
end

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

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

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

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

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

CSV.new('').unconverted_fields? # => nil
write_headers? → true or false Показать исходный код
# File lib/csv.rb, line 1944
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 2626
def build_fields_converter(initial_converters, options)
  fields_converter = FieldsConverter.new(options)
  normalize_converters(initial_converters).each do |name, converter|
    fields_converter.add_converter(name, &converter)
  end
  fields_converter
end
build_header_fields_converter() Показать исходный код
# File lib/csv.rb, line 2608
def build_header_fields_converter
  specific_options = {
    builtin_converters_name: :HeaderConverters,
    accept_nil: true,
  }
  options = @base_fields_converter_options.merge(specific_options)
  build_fields_converter(@initial_header_converters, options)
end
build_parser_fields_converter() Показать исходный код
# File lib/csv.rb, line 2596
def build_parser_fields_converter
  specific_options = {
    builtin_converters_name: :Converters,
  }
  options = @base_fields_converter_options.merge(specific_options)
  build_fields_converter(@initial_converters, options)
end
build_writer_fields_converter() Показать исходный код
# File lib/csv.rb, line 2621
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 2571
def convert_fields(fields, headers = false)
  if headers
    header_fields_converter.convert(fields, nil, 0)
  else
    parser_fields_converter.convert(fields, @headers, lineno)
  end
end

Обрабатывает fields с помощью @converters, или @header_converters, если headers передано как true, возвращая преобразованный набор полей. Любой преобразователь, изменяющий поле на что-либо кроме String, прерывает цепочку преобразований для этого поля. Это в первую очередь способ повышения эффективности.

determine_encoding(encoding, internal_encoding) Показать исходный код
# File lib/csv.rb, line 2534
def determine_encoding(encoding, internal_encoding)
  # honor the IO encoding if we can, otherwise default to ASCII-8BIT
  io_encoding = raw_encoding
  return io_encoding if io_encoding

  return Encoding.find(internal_encoding) if internal_encoding

  if encoding
    encoding, = encoding.split(":", 2) if encoding.is_a?(String)
    return Encoding.find(encoding)
  end

  Encoding.default_internal || Encoding.default_external
end
header_fields_converter() Показать исходный код
# File lib/csv.rb, line 2604
def header_fields_converter
  @header_fields_converter ||= build_header_fields_converter
end
normalize_converters(converters) Показать исходный код
# File lib/csv.rb, line 2549
def normalize_converters(converters)
  converters ||= []
  unless converters.is_a?(Array)
    converters = [converters]
  end
  converters.collect do |converter|
    case converter
    when Proc # custom code block
      [nil, converter]
    else # by name
      [converter, nil]
    end
  end
end
parser() Показать исходный код
# File lib/csv.rb, line 2634
def parser
  @parser ||= Parser.new(@io, parser_options)
end
parser_enumerator() Показать исходный код
# File lib/csv.rb, line 2643
def parser_enumerator
  @parser_enumerator ||= parser.parse
end
parser_fields_converter() Показать исходный код
# File lib/csv.rb, line 2592
def parser_fields_converter
  @parser_fields_converter ||= build_parser_fields_converter
end
parser_options() Показать исходный код
# File lib/csv.rb, line 2638
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 2582
def raw_encoding
  if @io.respond_to? :internal_encoding
    @io.internal_encoding || @io.external_encoding
  elsif @io.respond_to? :encoding
    @io.encoding
  else
    nil
  end
end

Возвращает кодировку внутреннего объекта IO.

writer() Показать исходный код
# File lib/csv.rb, line 2647
def writer
  @writer ||= Writer.new(@io, writer_options)
end
writer_fields_converter() Показать исходный код
# File lib/csv.rb, line 2617
def writer_fields_converter
  @writer_fields_converter ||= build_writer_fields_converter
end
writer_options() Показать исходный код
# File lib/csv.rb, line 2651
def writer_options
  @writer_options.merge(header_fields_converter: header_fields_converter,
                        fields_converter: writer_fields_converter)
end

Ruby Core © 1993–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

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