Spec-Zone.ru › Ruby 3.2

класс CSV

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

CSV

В спешке?

Если вы знакомы с данными CSV и у вас есть конкретная задача, вы можете перейти непосредственно к:

  • Рецепты для CSV.

В противном случае, продолжайте чтение о данном API: классах, методах и константах.

CSV

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

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

  • Разделитель столбцов отделяет поля в строке. Общим разделителем столбцов является запятая ",".

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

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

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

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

Класс CSV

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

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

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

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

require 'csv'

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

Упрощение

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

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

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

Методы разбора обычно возвращают:

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

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

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

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

  • Объект CSV::Table. Подробности см. в разделе CSV с заголовками.

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

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

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

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

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

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

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

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

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

Разбор по пути к файлу

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

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

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

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

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

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

Результат:

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

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

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

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

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

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

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

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

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

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

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

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

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

Результат:

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

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

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

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

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

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

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

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

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

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

Фильтрация CSV

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

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

Объекты CSV

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

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

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

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

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

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

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

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

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

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

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

  • IO#binmode

  • binmode?

  • IO#close

  • IO#close_read

  • IO#close_write

  • IO#closed?

  • eof

  • eof?

  • IO#external_encoding

  • IO#fcntl

  • IO#fileno

  • flock

  • IO#flush

  • IO#fsync

  • IO#internal_encoding

  • ioctl

  • IO#isatty

  • path

  • IO#pid

  • IO#pos

  • IO#pos=

  • IO#reopen

  • rewind

  • IO#seek

  • stat

  • IO#string

  • IO#sync

  • IO#sync=

  • IO#tell

  • to_i

  • to_io

  • IO#truncate

  • IO#tty?

Параметры

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

DEFAULT_OPTIONS = {
  # For both parsing and generating.
  col_sep:            ",",
  row_sep:            :auto,
  quote_char:         '"',
  # For parsing.
  field_size_limit:   nil,
  converters:         nil,
  unconverted_fields: nil,
  headers:            false,
  return_headers:     false,
  header_converters:  nil,
  skip_blanks:        false,
  skip_lines:         nil,
  liberal_parsing:    false,
  nil_value:          nil,
  empty_value:        "",
  strip:              false,
  # For generating.
  write_headers:      nil,
  quote_empty:        true,
  force_quotes:       false,
  write_converters:   nil,
  write_nil_value:    nil,
  write_empty_value:  "",
}

Параметры разбора

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

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

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

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

  • field_size_limit: Указывает максимальный размер поля + 1, разрешённый. Устарело с версии 3.2.3. Используйте max_field_size вместо этого.

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

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

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

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

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

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

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

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

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

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

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

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

Параметр row_sep

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Пример:

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

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

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

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

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

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

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

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

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

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

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, игнорируются строки, которые соответствуют ему.

  • Если String, он преобразуется в 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"]]

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

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

Выбрасывает исключение, если задан объект, который не является Regexp, String или 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 перед использованием.

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

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

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

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

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

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

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

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

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

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

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

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

Пример:

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

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

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

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

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

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

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

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), используемый для цитирования полей как при разборе, так и при генерации. Эта строка будет транскодирована в кодировку данных перед использованием.

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

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).

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Для того, чтобы методы парсинга получили доступ к сохранённым преобразователям в неглавных Ractors, структура хранения должна быть сначала сделана совместной. Поэтому, 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:

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

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

    • Преобразователь поля Proc.

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

Вывод:

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

Выход:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • Параметр header_converters с методом парсинга 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

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

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

DEFAULT_OPTIONS

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

DateMatcher

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

DateTimeMatcher

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

FieldInfo

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

index

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

line

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

header

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

quoted?

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

HeaderConverters

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

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

VERSION

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

Атрибуты

encoding[R]

:call-seq:

csv.encoding -> encoding

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

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

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

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

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

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

  # read, yield, write
  input.each do |row|
    yield row
    output << row
  end
end
  • Парсит CSV из источника (строка, поток ввода-вывода или ARGF).

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

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

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

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

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

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

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

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

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

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

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

FOO,0
BAR,-1
BAZ,-2

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

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

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

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

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

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

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

FOO,0
BAR,-1
BAZ,-2

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

FOO,0
BAR,-1
BAZ,-2

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

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

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

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

Аргументы:

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

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

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

foreach(path_or_io, mode='r', **options) {|row| ... ) Показать исходный код
foreach(path_or_io, mode='r', **options) → new_enumerator
# File lib/csv.rb, line 1331
def foreach(path, mode="r", **options, &block)
  return to_enum(__method__, path, mode, **options) unless block_given?
  open(path, mode, **options) do |csv|
    csv.each(&block)
  end
end

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

Ввод из файла без заголовков:

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

Вывод:

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

Ввод из файла с заголовками:

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

Вывод:

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

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

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

Вывод:

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

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

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

Вывод:

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

Без блока возвращает перечислитель:

string = "foo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)
CSV.foreach(path) # => #<Enumerator: CSV:foreach("t.csv", "r")>

Аргументы:

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

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

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

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

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

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

generate(csv_string, **options) {|csv| ... } Показать исходный код
generate(**options) {|csv| ... }
# File lib/csv.rb, line 1397
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, если задан, должен быть строковым объектом; по умолчанию — новая пустая строка.

  • Аргументы 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 не является строковым объектом:

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

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

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

Специальные параметры:

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

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

Для других options, см. Параметры генерации.

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

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

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

# Raises NoMethodError (undefined method `find' for :foo:Symbol)
CSV.generate_line(:foo)
generate_lines(rows) Показать исходный код
generate_lines(rows, **options)
# File lib/csv.rb, line 1500
def generate_lines(rows, **options)
  self.generate(**options) do |csv|
    rows.each do |row|
      csv << row
    end
  end
end

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

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

Специальные параметры:

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

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

Для других options, см. Параметры генерации.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  if data.is_a?(String)
    if encoding
      if encoding.is_a?(String)
        data_external_encoding, data_internal_encoding = encoding.split(":", 2)
        if data_internal_encoding
          data = data.encode(data_internal_encoding, data_external_encoding)
        else
          data = data.dup.force_encoding(data_external_encoding)
        end
      else
        data = data.dup.force_encoding(encoding)
      end
    end
    @io = StringIO.new(data)
  else
    @io = data
  end
  @encoding = determine_encoding(encoding, internal_encoding)

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

  if max_field_size.nil? and field_size_limit
    max_field_size = field_size_limit - 1
  end
  @parser_options = {
    column_separator: col_sep,
    row_separator: row_sep,
    quote_character: quote_char,
    max_field_size: max_field_size,
    unconverted_fields: unconverted_fields,
    headers: headers,
    return_headers: return_headers,
    skip_blanks: skip_blanks,
    skip_lines: skip_lines,
    liberal_parsing: liberal_parsing,
    encoding: @encoding,
    nil_value: nil_value,
    empty_value: empty_value,
    strip: strip,
  }
  @parser = nil
  @parser_enumerator = nil
  @eof_error = nil

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

# Raises ArgumentError (Cannot parse nil as CSV):
CSV.new(nil)
open(file_path, mode = "rb", **options ) → new_csv Показать исходный код
open(io, mode = "rb", **options ) → new_csv
open(file_path, mode = "rb", **options ) { |csv| ... } → object
open(io, mode = "rb", **options ) { |csv| ... } → object
# File lib/csv.rb, line 1580
def open(filename, mode="r", **options)
  # wrap a File opened with the remaining +args+ with no newline
  # decorator
  file_opts = options.dup
  unless file_opts.key?(:newline)
    file_opts[:universal_newline] ||= false
  end
  options.delete(:invalid)
  options.delete(:undef)
  options.delete(:replace)
  options.delete_if {|k, _| /newline\z/.match?(k)}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Создание объекта CSV с помощью пути к файлу:

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

Создание объекта CSV с помощью открытого файла:

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

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

С использованием пути к файлу:

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

Вывод:

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

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

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

Вывод:

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

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

# Raises TypeError (no implicit conversion of Symbol into String)
CSV.open(:foo)
parse(string) → array_of_arrays Показать исходный код
parse(io) → array_of_arrays
parse(string, headers: ..., **options) → csv_table
parse(io, headers: ..., **options) → csv_table
parse(string, **options) {|row| ... }
parse(io, **options) {|row| ... }
# File lib/csv.rb, line 1731
def parse(str, **options, &block)
  csv = new(str, **options)

  return csv.each(&block) if block_given?

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

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

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

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

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

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

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

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

Случай без {параметра headers}.

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

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

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

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

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

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

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

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

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

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

Вывод:

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

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

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

Вывод:

["foo", "0"]
["bar", "1"]
["baz", "2"]
С параметром headers

Случай с {параметром headers}.

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

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

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

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

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

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

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

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

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

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

Вывод:

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

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

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

Вывод:

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

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

# Raises NoMethodError (undefined method `close' for :foo:Symbol)
CSV.parse(:foo)
parse_line(string) → new_array or nil Показать исходный код
parse_line(io) → new_array or nil
parse_line(string, **options) → new_array or nil
parse_line(io, **options) → new_array or nil
parse_line(string, headers: true, **options) → csv_row or nil
parse_line(io, headers: true, **options) → csv_row or nil
# File lib/csv.rb, line 1804
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 1828
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 1836
def readlines(path, **options)
  read(path, **options)
end

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

table(source, **options) Показать исходный код
# File lib/csv.rb, line 1855
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 2371
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 2260
def binmode?
  if @io.respond_to?(:binmode?)
    @io.binmode?
  else
    false
  end
end
col_sep → string Показать исходный код
# File lib/csv.rb, line 2008
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 2442
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 2081
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 2553
def each(&block)
  return to_enum(__method__) unless block_given?
  begin
    while true
      yield(parser_enumerator.next)
    end
  rescue StopIteration
  end
end

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

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

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

Вывод:

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

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

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

Вывод:

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

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

string = "foo,0\nbar,1\nbaz,2\n"
csv = CSV.new(string)
csv.close
# Raises IOError (not opened for reading)
csv.each do |row|
  p row
end
eof()
Псевдоним для: eof?
eof?() Показать исходный код
# File lib/csv.rb, line 2296
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 2040
def field_size_limit
  parser.field_size_limit
end

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

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

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

flock(*args) Показать исходный код
# File lib/csv.rb, line 2268
def flock(*args)
  raise NotImplementedError unless @io.respond_to?(:flock)
  @io.flock(*args)
end
force_quotes? → true or false Показать исходный код
# File lib/csv.rb, line 2171
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 2508
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 2147
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 2630
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 2105
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 2689
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>"
END_OF_DOCUMENT_MARKER
ioctl(*args) Показать исходный код
# File lib/csv.rb, line 2273
def ioctl(*args)
  raise NotImplementedError unless @io.respond_to?(:ioctl)
  @io.ioctl(*args)
end
liberal_parsing? → true или false Показать исходный код
# File lib/csv.rb, line 2181
def liberal_parsing?
  parser.liberal_parsing?
end

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

CSV.new('').liberal_parsing? # => false
line → массив Показать исходный код
# File lib/csv.rb, line 2246
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 2222
def lineno
  if @writer
    @writer.lineno
  else
    parser.lineno
  end
end

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

Парсинг:

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

Вывод:

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

Генерация:

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

Вывод:

0
1
2
max_field_size → целое число или nil Показать исходный код
# File lib/csv.rb, line 2052
def max_field_size
  parser.max_field_size
end

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

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

С версии 3.2.3.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

CSV.new('').return_headers? # => false
rewind() Показать исходный код
# File lib/csv.rb, line 2311
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 2018
def row_sep
  parser.row_separator
end

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

CSV.new('').row_sep # => "\n"
shift → массив, csv_row или nil Показать исходный код
# File lib/csv.rb, line 2667
def shift
  if @eof_error
    eof_error, @eof_error = @eof_error, nil
    raise eof_error
  end
  begin
    parser_enumerator.next
  rescue StopIteration
    nil
  end
end

Возвращает следующую строку данных как:

  • Массив, если заголовки не используются.

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

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

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

string = "foo,0\nbar,1\nbaz,2\n"
csv = CSV.new(string)
csv.shift # => ["foo", "0"]
csv.shift # => ["bar", "1"]
csv.shift # => ["baz", "2"]
csv.shift # => nil

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

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

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

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

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

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

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

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

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

CSV.new('').unconverted_fields? # => nil
write_headers? → true или false Показать исходный код
# File lib/csv.rb, line 2133
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 2821
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 2803
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 2791
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 2816
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 2766
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 2729
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 2799
def header_fields_converter
  @header_fields_converter ||= build_header_fields_converter
end
normalize_converters(converters) Показать исходный код
# File lib/csv.rb, line 2744
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 2829
def parser
  @parser ||= Parser.new(@io, parser_options)
end
parser_enumerator() Показать исходный код
# File lib/csv.rb, line 2838
def parser_enumerator
  @parser_enumerator ||= parser.parse
end
parser_fields_converter() Показать исходный код
# File lib/csv.rb, line 2787
def parser_fields_converter
  @parser_fields_converter ||= build_parser_fields_converter
end
parser_options() Показать исходный код
# File lib/csv.rb, line 2833
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 2777
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 2842
def writer
  @writer ||= Writer.new(@io, writer_options)
end
writer_fields_converter() Показать исходный код
# File lib/csv.rb, line 2812
def writer_fields_converter
  @writer_fields_converter ||= build_writer_fields_converter
end
writer_options() Показать исходный код
# File lib/csv.rb, line 2846
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