類別 CSV

CSV

CSV Data

CSV(逗號分隔值)資料是表格的文字表示

這個 CSV 字串,列分隔符號為"\n",欄分隔符號為",",有 3 列和 2 行

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

儘管名稱為 CSV,CSV 表示法可以使用不同的分隔符號。

有關表格的更多資訊,請參閱維基百科條目「表格(資訊)」,特別是其「簡單表格」部分

類別 CSV

Class CSV 提供下列方法

讓 CSV 可用

require 'csv'

這裡的所有範例都假設已執行此動作。

簡化操作

CSV 物件有數十個執行個體方法,可提供剖析和產生 CSV 資料的細微控制。但對於許多需求而言,較簡單的方法就足夠了。

本節摘要 CSV 中的單例方法,讓您無需明確建立 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#parse_csv 擴充 String 類別,它也僅傳回第一列

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#to_csv 擴充 Array 類別,它會將陣列轉換成字串

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

「過濾」CSV

方法 CSV.filter 提供 Unix 風格的 CSV 資料過濾器。輸入資料會經過處理,以形成輸出資料

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

CSV 物件

有三個方法可以建立 CSV 物件

實例方法

CSV 有三組實例方法

委派的方法

為了方便起見,CSV 物件會委派給類別 IO 中的許多方法。(其中少數在 CSV 中有包裝器「防護程式碼」。)您可以呼叫

選項

選項的預設值為

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

指定列分隔符號,為字串或符號 :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 ($/)

很明顯地,偵測需要一點時間。如果速度很重要,請手動 設定。另請注意,如果要使用此功能,應在 Windows 上以二進位模式開啟 IO 物件,因為行尾轉換可能會導致將文件位置重設為讀取前的位置時發生問題。

選項 col_sep

指定要同時用於剖析和產生的字串欄位分隔符號。使用前,字串會轉碼成資料的編碼。

預設值

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

使用預設值(逗號)

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

使用 :(冒號)

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

使用 ::(兩個冒號)

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

使用 ''(空字串)

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

如果使用空字串剖析,會引發例外狀況

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

指定用於同時在剖析和產生中引述欄位的字元(長度為 1 的字串)。使用前,這個 字串 會轉碼成資料的編碼。

預設值

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_fieldstrue 時,每個傳回的列(陣列或 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,會使用目前的 options 呼叫方法 CSV::parse_line(str, 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 相同,但

此區段假設之前已執行

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

指定物件,用於識別輸入中要忽略的註解列

預設值

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

本節範例

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

使用預設值 nil

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

使用 Regexp

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

使用字串

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

如果給定的物件不是 Regexp、字串或 nil,則會引發例外狀況

# Raises ArgumentError (:skip_lines has to respond to #match: 0)
CSV.parse(str, skip_lines: 0)
選項 strip

指定布林值,用於判斷是否從每個輸入欄位移除空白。

預設值

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

預設值為 false

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

值為 true

ary = CSV.parse_line(' a , b ', strip: true)
ary # => ["a", "b"]
選項 liberal_parsing

指定布林值或雜湊值,用於判斷 CSV 是否會嘗試剖析不符合 RFC 4180 的輸入,例如未加引號欄位中的雙引號。

預設值

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

以下兩個範例

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

沒有 liberal_parsing

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

liberal_parsing

ary = CSV.parse_line(str, liberal_parsing: true)
ary # => ["is", "this \"three", " or four\"", "fields"]

使用 backslash_quote 子選項剖析使用反斜線跳脫雙引號字元的數值。這會讓剖析器將 \" 視為 ""

以下兩個範例

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

liberal_parsing,但沒有 backslash_quote 子選項

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

liberal_parsing 及其 backslash_quote 子選項

ary = CSV.parse_line(str, liberal_parsing: { backslash_quote: true })
ary # => ["Show", "Harry \"Handcuff\" Houdini, the one and only", "Tampa Theater"]
puts ary[1] # => Harry "Handcuff" Houdini, the one and only
選項 nil_value

指定要替換每個空值(無文字)欄位的物件。

預設值

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

使用預設值 nil

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

使用不同的物件

CSV.parse_line('a,,b,,c', nil_value: 0) # => ["a", 0, "b", 0, "c"]
選項 empty_value

指定要替換每個具有空字串的欄位的物件。

預設值

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

使用預設值 ""

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

使用不同的物件

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

產生選項

產生選項,如下詳細說明,包括

選項 row_sep

指定列分隔符號,為字串或符號 :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 ($/)

很明顯地,偵測需要一點時間。如果速度很重要,請手動 設定。另請注意,如果要使用此功能,應在 Windows 上以二進位模式開啟 IO 物件,因為行尾轉換可能會導致將文件位置重設為讀取前的位置時發生問題。

選項 col_sep

指定要同時用於剖析和產生的字串欄位分隔符號。使用前,字串會轉碼成資料的編碼。

預設值

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

使用預設值(逗號)

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

使用 :(冒號)

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

使用 ::(兩個冒號)

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

使用 ''(空字串)

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

如果使用空字串剖析,會引發例外狀況

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

指定用於同時在剖析和產生中引述欄位的字元(長度為 1 的字串)。使用前,這個 字串 會轉碼成資料的編碼。

預設值

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

這對於不正確地使用 '(單引號)來引述欄位(而不是正確的 "(雙引號))的應用程式很有用。

使用預設值(雙引號)

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

使用 '(單引號)

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

如果字串長度大於 1,會引發例外狀況

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

如果值不是字串,會引發例外狀況

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

指定布林值,用於判斷輸出是否包含標題列;如果沒有標題,則忽略。

預設值

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

不使用 write_headers

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

使用 write_headers

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

指定布林值,用於判斷是否要對每個輸出欄位加上雙引號。

預設值

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

本節範例

ary = ['foo', 0, nil]

使用預設值 false

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

使用 true

str = CSV.generate_line(ary, force_quotes: true)
str # => "\"foo\",\"0\",\"\"\n"
選項 quote_empty

指定布林值,用於判斷是否要對空值加上雙引號。

預設值

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

使用預設值 true

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

使用 false

CSV.generate_line(['"', ""], quote_empty: false) # => "\"\"\"\",\n"
選項 write_converters

指定產生欄位時要使用的轉換器。請參閱 寫入轉換器

預設值

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

不使用寫入轉換器

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

使用寫入轉換器

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

使用兩個寫入轉換器(依序呼叫)

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

另請參閱 寫入轉換器

選項 write_nil_value

指定要替換每個 nil 值欄位的物件。

預設值

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

不使用選項

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

使用選項

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

指定要替換每個具有空字串的欄位的物件。

預設值

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

不使用選項

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

使用選項

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

具有標題的 CSV

CSV 允許指定 CSV 檔案的欄位名稱,無論它們是在資料中,或另外提供。如果指定標頭,讀取方法會傳回 CSV::Table 的執行個體,它包含 CSV::Row

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

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

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

轉換器

預設情況下,CSV 解析的每個值(欄位或標頭)會形成字串。你可以使用欄位轉換器標頭轉換器來攔截並修改已解析的值

此外,預設情況下,在產生期間要寫入的每個值會「原樣」寫入。你可以使用寫入轉換器來修改寫入前的值。

指定轉換器

你可以在各種 CSV 方法的 options 參數中指定轉換器,以進行解析或產生

有三個表單可指定轉換器

轉換器程序

這個轉換器程序 strip_converter 接受值 field 並傳回 field.strip

strip_converter = proc {|field| field.strip }

在此呼叫 CSV.parse 中,關鍵字參數 converters: string_converter 指定

範例

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

轉換器程序可以接收第二個引數 field_info,其中包含欄位的詳細資料。這個修改過的 strip_converter 會顯示其引數

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

輸出

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

每個 CSV::FieldInfo 物件會顯示

儲存的轉換器

可以為轉換器指定名稱並儲存在結構中,解析方法可以透過名稱找到它。

欄位轉換器的儲存結構是雜湊 CSV::Converters。它有幾個內建的轉換器程序

。這個範例會建立一個轉換器程序,然後儲存它

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,其工作方式相同。它也有內建的轉換器程序

沒有這樣的儲存結構來寫入標頭。

為了讓解析方法存取非主 Ractor 中的儲存轉換器,必須先讓儲存結構可共用。因此,必須在使用儲存在這些結構中的轉換器的 Ractor 建立之前,呼叫 Ractor.make_shareable(CSV::Converters)Ractor.make_shareable(CSV::HeaderConverters)。(由於讓儲存結構可共用會涉及凍結它們,因此必須先新增任何要使用的自訂轉換器。)

轉換器清單

轉換器 清單 是陣列,可以包含任何種類的

範例

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 所做的。)

使用欄位轉換器有下列三種方式。

安裝欄位轉換器不會影響已讀取的列

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

有其他內建轉換器,同時也支援自訂轉換器。

內建欄位轉換器

內建欄位轉換器在雜湊 CSV::Converters

顯示

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

輸出

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

這些轉換器會在嘗試轉換之前將值轉碼為 UTF-8。如果無法將值轉碼為 UTF-8,轉換就會失敗,而值將保持未轉換。

轉換器 :integer 會轉換 Integer() 接受的每個欄位

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

轉換器 :float 會轉換 Float() 接受的每個欄位

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

轉換器 :numeric 會使用 :integer:float 轉換。

轉換器 :date 會轉換 Date::parse 接受的每個欄位

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

轉換器 :date_time 會轉換 DateTime::parse 接受的每個欄位

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

轉換器 :numeric 會使用 :date_time:numeric 轉換。

如上所見,方法 convert 會將轉換器新增到 CSV 執行個體,而方法 converters 會傳回目前生效的轉換器陣列

csv = CSV.new('0,1,2')
csv.converters # => []
csv.convert(:integer)
csv.converters # => [:integer]
csv.convert(:date)
csv.converters # => [:integer, :date]
自訂欄位轉換器

您可以定義自訂欄位轉換器

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

您可以在 Converters 雜湊中註冊轉換器,這讓您可以透過名稱來參考它

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

標頭轉換器

標頭轉換器只會在標頭上運作 (不會在其他列上運作)。

使用標頭轉換器有下列三種方式;這些範例使用內建標頭轉換器 :downcase,它會將每個已解析標頭轉換成小寫。

內建標頭轉換器

內建標頭轉換器位於雜湊 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。剖析器會在 IOString 物件的 編碼 中執行,這些物件會從中讀取或寫入資料。您的資料永遠不會被轉碼(除非您要求 Ruby 為您轉碼),而且會直接在它所在的 編碼 中被剖析。因此,CSV 會傳回陣列或列,這些陣列或列中的字串會使用您的資料的 編碼。這是透過將剖析器本身轉碼成您的 編碼 來完成的。

當然,為了達成這個多編碼支援,必須進行一些轉碼。例如,:col_sep:row_sep:quote_char 必須被轉碼,以符合您的資料。希望這會讓整個程序感覺起來很透明,因為 CSV 的預設值應該會神奇地適用於您的資料。不過,您可以在目標 編碼 中手動設定這些值,以避免轉換。

另外,值得注意的是,雖然 CSV 的所有核心剖析器現在都與 編碼 無關,但有些功能並非如此。例如,內建轉換器會嘗試在進行轉換之前將資料轉碼為 UTF-8。同樣地,您可以提供自訂轉換器,這些轉換器會知道您的編碼,以避免這個轉換。對於我來說,要支援 Ruby 的所有編碼中的原生轉換實在太困難了。

無論如何,這方面的實務很簡單:確保傳遞給 IOString 物件的 CSV 已設定適當的 Encoding,一切應該都能正常運作。允許您開啟 IO 物件(CSV::foreach()CSV::open()CSV::read()CSV::readlines())的 CSV 方法允許您指定 Encoding

當使用與 ASCII 不相容的 EncodingCSV 產生到 String 時,會出現一個小例外。沒有現有的資料可供 CSV 用來準備自己,因此您可能需要手動指定大多數情況下所需的 Encoding。不過,當使用 CSV::generate_line() 或 Array#to_csv() 時,它會嘗試使用輸出列中的欄位來猜測。

我會在方法的說明文件中指出任何其他 Encoding 問題,因為它們會出現。

這已經過我最大的能力測試,使用 Ruby 附帶的所有非「虛擬」編碼。但是,它是全新的程式碼,可能有一些錯誤。請隨時 回報 您發現的任何問題。

常數

ConverterEncoding

所有轉換器使用的編碼。

轉換器

包含內建欄位轉換器的名稱和程序的雜湊。請參閱 內建欄位轉換器

這個雜湊故意不凍結,並且可以用自訂欄位轉換器來擴充。請參閱 自訂欄位轉換器

DEFAULT_OPTIONS

方法選項的預設值。

DateMatcher

用於尋找和轉換一些常見 Date 格式的 Regexp

DateTimeMatcher

用於尋找和轉換一些常見 DateTime 格式的 Regexp

FieldInfo

一個 FieldInfo Struct 包含從其讀取資料來源中欄位的詳細資訊。 CSV 會將這個 Struct 傳遞給根據欄位結構做出決定的某些區塊。請參閱 CSV.convert_fields() 以取得範例。

索引

欄位在其列中的以零為基準的索引。

此列來自資料來源的列。

標頭

欄位的標頭(如果可用)。

已引號?

True 或 false,表示原始值是否已引號。

HeaderConverters

包含內建標頭轉換器的名稱和 Procs 的 Hash。請參閱 內建標頭轉換器

此 Hash 故意保留未凍結,並可以使用自訂欄位轉換器進行擴充。請參閱 自訂標頭轉換器

版本

已安裝函式庫的版本。

屬性

編碼[R]

:call-seq

csv.encoding -> encoding

傳回用於剖析和產生的編碼;請參閱 字元編碼 (M17n 或多語言化)

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

公開類別方法

filter(in_string_or_io, **options) {|row| ... } → array_of_arrays 或 csv_table 按一下以切換來源
filter(in_string_or_io, out_string_or_io, **options) {|row| ... } → array_of_arrays 或 csv_table
filter(**options) {|row| ... } → array_of_arrays 或 csv_table
  • 從來源 (字串、IO 串流或 ARGF) 剖析 CSV。

  • 使用每個剖析列呼叫指定的區塊

    • 沒有標頭,每列都是陣列。

    • 有標頭,每列都是 CSV::Row

  • 產生 CSV 至輸出 (字串、IO 串流或 STDOUT)。

  • 傳回剖析的來源

    • 沒有標頭,陣列的陣列。

    • 有標頭,CSV::Table

當提供 in_string_or_io,但未提供 out_string_or_io 時,從指定的 in_string_or_io 剖析並產生至 STDOUT。

沒有標頭的字串輸入

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

輸出 (至 STDOUT)

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>

輸出 (至 STDOUT)

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

沒有標頭的 IO 串流輸入

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

輸出 (至 STDOUT)

FOO,0
BAR,-1
BAZ,-2

有標頭的 IO 串流輸入

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>

輸出 (至 STDOUT)

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

當同時提供 in_string_or_ioout_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"

沒有標頭的 IO 串流輸出

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"

有標頭的 IO 串流輸出

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_ioout_string_or_io 時,會從 ARGF 進行剖析並產生至 STDOUT。

沒有標頭

# 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")

輸出 (至 STDOUT)

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

輸出 (至 STDOUT)

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

參數

  • 參數 in_string_or_io 必須是字串或 IO 串流。

  • 參數 out_string_or_io 必須是字串或 IO 串流。

  • 參數 **options 必須是關鍵字選項。請參閱 剖析選項

# File lib/csv.rb, line 1202
def filter(input=nil, output=nil, **options)
  # parse options for input, output, or both
  in_options, out_options = Hash.new, {row_sep: InputRecordSeparator.value}
  options.each do |key, value|
    case key
    when /\Ain(?:put)?_(.+)\Z/
      in_options[$1.to_sym] = value
    when /\Aout(?:put)?_(.+)\Z/
      out_options[$1.to_sym] = value
    else
      in_options[key]  = value
      out_options[key] = value
    end
  end

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

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

  # read, yield, write
  input.each do |row|
    yield row
    output << row
  end
end
foreach(path_or_io, mode='r', **options) {|row| ... ) 按一下以切換來源
foreach(path_or_io, mode='r', **options) → new_enumerator

使用從來源 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">

沒有標頭的 IO 串流輸入

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

有標頭的 IO 串流輸入

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

如果沒有提供區塊,則傳回 Enumerator

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 必須是檔案路徑或 IO 串流。

  • 如果提供了參數 mode,則必須是檔案模式。請參閱 存取模式

  • 參數 **options 必須是關鍵字選項。請參閱 剖析選項

  • 此方法選擇性地接受其他 :encoding 選項,您可以使用此選項指定從 pathio 讀取的資料的 編碼。除非您的資料採用 Encoding::default_external 給定的編碼,否則您必須提供此選項。剖析會使用此選項來決定如何剖析資料。您可以提供第二個 編碼,以便在讀取資料時對其進行轉碼。例如,

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

    會從檔案讀取 UTF-32BE 資料,但在剖析之前將其轉碼為 UTF-8

# File lib/csv.rb, line 1332
def foreach(path, mode="r", **options, &block)
  return to_enum(__method__, path, mode, **options) unless block_given?
  open(path, mode, **options) do |csv|
    csv.each(&block)
  end
end
generate(csv_string, **options) {|csv| ... } 按一下以切換來源
generate(**options) {|csv| ... }
  • 如果提供了參數 csv_string,則必須是字串物件;預設為新的空白字串。

  • 如果提供了參數 options,則應該是產生選項。請參閱 產生選項


透過 CSV.new(csv_string, **options) 建立新的 CSV 物件;使用 CSV 物件呼叫區塊,區塊可能會修改 CSV 物件;傳回從 CSV 物件產生的字串。

請注意,傳遞的字串被此方法修改。如果字串必須保留,請傳遞 csv_string.dup。

此方法有一個額外的選項::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)
# File lib/csv.rb, line 1398
def generate(str=nil, **options)
  encoding = options[:encoding]
  # add a default empty String, if none was given
  if str
    str = StringIO.new(str)
    str.seek(0, IO::SEEK_END)
    str.set_encoding(encoding) if encoding
  else
    str = +""
    str.force_encoding(encoding) if encoding
  end
  csv = new(str, **options) # wrap
  yield csv         # yield for appending
  csv.string        # return final String
end
generate_line(ary) 按一下以切換來源
generate_line(ary, **options)

傳回使用指定的 optionsary 產生 CSV 所建立的字串。

引數 ary 必須是陣列。

特殊選項

  • 選項 :row_sep 預設為 "\n"> 在 Ruby 3.0 或更新版本,否則為 <tt>$INPUT_RECORD_SEPARATOR ($/)。

    $INPUT_RECORD_SEPARATOR # => "\n"
    
  • 此方法接受一個額外的選項::encoding,用於設定輸出的基礎 編碼。如果可能,此方法會嘗試從 row 中的第一個非 nil 欄位猜測你的 編碼,但你可能需要使用此參數作為備用計畫。

對於其他 options,請參閱 產生選項


傳回從陣列產生的字串

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

如果 ary 不是陣列,則會引發例外

# Raises NoMethodError (undefined method `find' for :foo:Symbol)
CSV.generate_line(:foo)
# File lib/csv.rb, line 1446
def generate_line(row, **options)
  options = {row_sep: InputRecordSeparator.value}.merge(options)
  str = +""
  if options[:encoding]
    str.force_encoding(options[:encoding])
  else
    fallback_encoding = nil
    output_encoding = nil
    row.each do |field|
      next unless field.is_a?(String)
      fallback_encoding ||= field.encoding
      next if field.ascii_only?
      output_encoding = field.encoding
      break
    end
    output_encoding ||= fallback_encoding
    if output_encoding
      str.force_encoding(output_encoding)
    end
  end
  (new(str, **options) << row).string
end
generate_lines(rows) 按一下以切換來源
generate_lines(rows, **options)

傳回使用指定的 optionsary 產生 CSV 所建立的字串。

引數 rows 必須是列的陣列。 是字串或 CSV::Row 的陣列。

特殊選項

  • 選項 :row_sep 預設為 "\n" 在 Ruby 3.0 或更新版本,否則為 $INPUT_RECORD_SEPARATOR ($/)。

    $INPUT_RECORD_SEPARATOR # => "\n"
    
  • 此方法接受一個額外的選項::encoding,用於設定輸出的基礎 編碼。如果可能,此方法會嘗試從 row 中的第一個非 nil 欄位猜測你的 編碼,但你可能需要使用此參數作為備用計畫。

對於其他 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)
# File lib/csv.rb, line 1501
def generate_lines(rows, **options)
  self.generate(**options) do |csv|
    rows.each do |row|
      csv << row
    end
  end
end
instance(string, **options) 按一下以切換來源
instance(io = $stdout, **options)
instance(string, **options) {|csv| ... }
instance(io = $stdout, **options) {|csv| ... }

建立或擷取快取的 CSV 物件。有關引數和選項,請參閱 CSV.new

此 API 不支援 Ractor。


如果未提供區塊,則傳回 CSV 物件。

第一次呼叫 instance 會建立並快取 CSV 物件

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

使用相同的 stringio 再次呼叫 instance 會擷取相同的快取物件

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

使用不同的 stringio 再次呼叫 instance 會建立並快取不同的 CSV 物件。

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

所有快取的物件都保持可用

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

如果提供區塊,則呼叫區塊並傳入已建立或擷取的 CSV 物件;傳回區塊的傳回值

CSV.instance(s0) {|csv| :foo } # => :foo
# File lib/csv.rb, line 1006
def instance(data = $stdout, **options)
  # create a _signature_ for this method call, data object and options
  sig = [data.object_id] +
        options.values_at(*DEFAULT_OPTIONS.keys)

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

  if block_given?
    yield instance  # run block, if given, returning result
  else
    instance        # or return the instance
  end
end
new(string) 按一下以切換來源
new(io)
new(string, **options)
new(io, **options)

傳回使用 stringio 和指定的 options 建立的新 CSV 物件。

  • 引數 string 應該是 String 物件;它會放入新的 StringIO 物件中,並置於開頭。

  • 引數 io 應該是 IO 物件,其

    • 已開啟可讀取;傳回時,IO 物件會關閉。

    • 置於開頭。如需置於結尾以進行附加,請使用 CSV.generate 方法。對於任何其他定位,請改為傳遞預設的 StringIO 物件。

  • 引數 options:請參閱

    由於效能考量,無法在 CSV 物件中覆寫選項,因此在此指定的選項會持續存在。

除了 CSV 執行個體方法之外,還委派了多個 IO 方法。請參閱 委派的方法


從 String 物件建立 CSV 物件

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

從 File 物件建立 CSV 物件

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

如果引數為 nil,則會引發例外狀況

# Raises ArgumentError (Cannot parse nil as CSV):
CSV.new(nil)
# File lib/csv.rb, line 1905
def initialize(data,
               col_sep: ",",
               row_sep: :auto,
               quote_char: '"',
               field_size_limit: nil,
               max_field_size: nil,
               converters: nil,
               unconverted_fields: nil,
               headers: false,
               return_headers: false,
               write_headers: nil,
               header_converters: nil,
               skip_blanks: false,
               force_quotes: false,
               skip_lines: nil,
               liberal_parsing: false,
               internal_encoding: nil,
               external_encoding: nil,
               encoding: nil,
               nil_value: nil,
               empty_value: "",
               strip: false,
               quote_empty: true,
               write_converters: nil,
               write_nil_value: nil,
               write_empty_value: "")
  raise ArgumentError.new("Cannot parse nil as CSV") if data.nil?

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

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

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

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

  @writer = nil
  writer if @writer_options[:write_headers]
end
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

可能的選項元素

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 選項,您可以使用此選項指定從 pathio 讀取的資料的 編碼。除非您的資料採用 Encoding::default_external 給定的編碼,否則您必須提供此選項。剖析會使用此選項來決定如何剖析資料。您可以提供第二個 編碼,以便在讀取資料時對其進行轉碼。例如,

    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:"\"">

如果引數不是字串物件或 IO 物件,則擲回例外

# Raises TypeError (no implicit conversion of Symbol into String)
CSV.open(:foo)
# File lib/csv.rb, line 1581
def open(filename, mode="r", **options)
  # wrap a File opened with the remaining +args+ with no newline
  # decorator
  file_opts = options.dup
  unless file_opts.key?(:newline)
    file_opts[:universal_newline] ||= false
  end
  options.delete(:invalid)
  options.delete(:undef)
  options.delete(:replace)
  options.delete_if {|k, _| /newline\z/.match?(k)}

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

  # handle blocks like Ruby's open(), not like the CSV library
  if block_given?
    begin
      yield csv
    ensure
      csv.close
    end
  else
    csv
  end
end
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| ... }

使用指定的 options 分析 stringio

  • 引數 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">

如果引數不是字串物件或 IO 物件,則擲回例外

# Raises NoMethodError (undefined method `close' for :foo:Symbol)
CSV.parse(:foo)
# File lib/csv.rb, line 1732
def parse(str, **options, &block)
  csv = new(str, **options)

  return csv.each(&block) if block_given?

  # slurp contents, if no block is given
  begin
    csv.read
  ensure
    csv.close
  end
end
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

傳回使用指定的 options 分析 stringio 的第一列所建立的資料。

  • 引數 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)

分析字串物件的第一列

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)

分析字串物件的第一列

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

分析 File 物件的第一列

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

如果引數為 nil,則會引發例外狀況

# Raises ArgumentError (Cannot parse nil as CSV):
CSV.parse_line(nil)
# File lib/csv.rb, line 1805
def parse_line(line, **options)
  new(line, **options).each.first
end
read(source, **options) → array_of_arrays 按一下以切換來源
read(source, headers: true, **options) → csv_table

使用指定的 options 開啟指定的 source(請參閱 CSV.open),讀取來源(請參閱 CSV#read),然後傳回結果,結果會是陣列陣列或 CSV::Table

沒有標頭

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

有標頭

string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)
CSV.read(path, headers: true) # => #<CSV::Table mode:col_or_row row_count:4>
# File lib/csv.rb, line 1829
def read(path, **options)
  open(path, **options) { |csv| csv.read }
end
readlines(source, **options) 按一下以切換來源

別名為 CSV.read

# File lib/csv.rb, line 1837
def readlines(path, **options)
  read(path, **options)
end
table(source, **options) 按一下以切換來源

使用 sourceoptions 和某些預設選項呼叫 CSV.read

  • headerstrue

  • converters:numeric

  • header_converters:symbol

傳回 CSV::Table 物件。

範例

string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)
CSV.table(path) # => #<CSV::Table mode:col_or_row row_count:4>
# File lib/csv.rb, line 1856
def table(path, **options)
  default_options = {
    headers:           true,
    converters:        :numeric,
    header_converters: :symbol,
  }
  options = default_options.merge(options)
  read(path, **options)
end

公開實體方法

csv << row → self 按一下以切換來源

將列新增至 self

  • 引數 row 必須是陣列物件或 CSV::Row 物件。

  • 輸出串流必須開啟才能寫入。


新增陣列

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

新增 CSV::Rows

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

CSV::Row 物件中的標頭不會新增

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

如果 row 不是陣列或 CSV::Row,則會擲回例外狀況

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

如果輸出串流未開啟以進行寫入,則會擲回例外狀況

path = 't.csv'
File.write(path, '')
File.open(path) do |file|
  CSV.open(file) do |csv|
    # Raises IOError (not opened for writing)
    csv << ['foo', 0]
  end
end
# File lib/csv.rb, line 2372
def <<(row)
  writer << row
  self
end
別名為:add_rowputs
add_row
別名為:<<
binmode?() 按一下以切換來源
# File lib/csv.rb, line 2261
def binmode?
  if @io.respond_to?(:binmode?)
    @io.binmode?
  else
    false
  end
end
col_sep → string 按一下以切換來源

傳回編碼的欄位分隔符號;用於剖析和寫入;請參閱 {選項 col_sep}

CSV.new('').col_sep # => ","
# File lib/csv.rb, line 2009
def col_sep
  parser.column_separator
end
convert(converter_name) → array_of_procs 按一下以切換來源
轉換 {|field, field_info| ... } → 程序陣列
  • 沒有區塊時,安裝欄位轉換器(一個程序)。

  • 有區塊時,定義並安裝自訂欄位轉換器。

  • 傳回已安裝欄位轉換器的陣列。

  • 如果提供引數 converter_name,應為現有欄位轉換器的名稱。

請參閱 欄位轉換器


沒有區塊時,安裝欄位轉換器

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

如果提供區塊,則會針對每個欄位呼叫該區塊

  • 引數 field 是欄位值。

  • 引數 field_infoCSV::FieldInfo 物件,其中包含欄位的詳細資料。

此處的範例假設先前執行

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

提供區塊的範例

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

輸出

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

區塊不必傳回字串物件

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

如果提供 converter_name,則不會呼叫區塊

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

如果 converter_name 不是內建欄位轉換器的名稱,則會引發解析時間例外狀況

csv = CSV.open(path)
csv.convert(:nosuch) => [nil]
# Raises NoMethodError (undefined method `arity' for nil:NilClass)
csv.read
# File lib/csv.rb, line 2443
def convert(name = nil, &converter)
  parser_fields_converter.add_converter(name, &converter)
end
converters → array 按一下以切換來源

傳回包含欄位轉換器的陣列;請參閱 欄位轉換器

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

請注意,您需要在主 Ractor 上呼叫 +Ractor.make_shareable(CSV::Converters)+,才能使用這個方法。

# File lib/csv.rb, line 2082
def converters
  parser_fields_converter.map do |converter|
    name = Converters.rassoc(converter)
    name ? name.first : converter
  end
end
each → enumerator 按一下以切換來源
each {|row| ...}

使用每個後續列呼叫區塊。資料來源必須開啟以供讀取。

沒有標頭

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

輸出

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

有標頭

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

輸出

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

如果來源未開啟以供讀取,則會引發例外狀況

string = "foo,0\nbar,1\nbaz,2\n"
csv = CSV.new(string)
csv.close
# Raises IOError (not opened for reading)
csv.each do |row|
  p row
end
# File lib/csv.rb, line 2554
def each(&block)
  return to_enum(__method__) unless block_given?
  begin
    while true
      yield(parser_enumerator.next)
    end
  rescue StopIteration
  end
end
eof()
別名:eof?
eof?() 按一下以切換來源
# File lib/csv.rb, line 2297
def eof?
  return false if @eof_error
  begin
    parser_enumerator.peek
    false
  rescue MalformedCSVError => error
    @eof_error = error
    false
  rescue StopIteration
    true
  end
end
也別名為:eof
field_size_limit → 整數或 nil 按一下以切換來源

傳回欄位大小的限制;用於解析;請參閱 {選項 field_size_limit}

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

自 3.2.3 起已棄用。請改用 max_field_size

# File lib/csv.rb, line 2041
def field_size_limit
  parser.field_size_limit
end
flock(*args) 按一下以切換來源
# File lib/csv.rb, line 2269
def flock(*args)
  raise NotImplementedError unless @io.respond_to?(:flock)
  @io.flock(*args)
end
force_quotes? → true 或 false 按一下以切換來源

傳回決定是否要引用所有輸出欄位的數值;用於產生;請參閱 {Option force_quotes}

CSV.new('').force_quotes? # => false
# File lib/csv.rb, line 2172
def force_quotes?
  @writer_options[:force_quotes]
end
取得
別名為: shift
header_convert(name = nil, &converter) 按一下以切換來源

區塊不必傳回字串物件

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

如果提供 converter_name,則不會呼叫區塊

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

如果 converter_name 不是內建欄位轉換器的名稱,則會引發解析時間例外狀況

csv = CSV.open(path, headers: true)
csv.header_convert(:nosuch)
# Raises NoMethodError (undefined method `arity' for nil:NilClass)
csv.read
# File lib/csv.rb, line 2509
def header_convert(name = nil, &converter)
  header_fields_converter.add_converter(name, &converter)
end
header_converters → 陣列 按一下以切換來源

傳回包含標頭轉換器的陣列;用於剖析;請參閱 標頭轉換器

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

請注意,您需要在主 Ractor 上呼叫 +Ractor.make_shareable(CSV::HeaderConverters)+ 才能使用此方法。

# File lib/csv.rb, line 2148
def header_converters
  header_fields_converter.map do |converter|
    name = HeaderConverters.rassoc(converter)
    name ? name.first : converter
  end
end
header_row? → true 或 false 按一下以切換來源

如果要讀取的下一個列是標頭列,則傳回 true;否則傳回 false

沒有標頭

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

有標頭

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

如果來源未開啟以供讀取,則會引發例外狀況

string = "foo,0\nbar,1\nbaz,2\n"
csv = CSV.new(string)
csv.close
# Raises IOError (not opened for reading)
csv.header_row?
# File lib/csv.rb, line 2631
def header_row?
  parser.header_row?
end
headers → 物件 按一下以切換來源

傳回決定是否使用標頭的數值;用於剖析;請參閱 {Option headers}

CSV.new('').headers # => nil
# File lib/csv.rb, line 2106
def headers
  if @writer
    @writer.headers
  else
    parsed_headers = parser.headers
    return parsed_headers if parsed_headers
    raw_headers = @parser_options[:headers]
    raw_headers = nil if raw_headers == false
    raw_headers
  end
end
inspect → 字串 按一下以切換來源

傳回顯示 self 的特定屬性的字串

string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
csv = CSV.new(string, headers: true)
s = csv.inspect
s # => "#<CSV io_type:StringIO encoding:UTF-8 lineno:0 col_sep:\",\" row_sep:\"\\n\" quote_char:\"\\\"\" headers:true>"
# File lib/csv.rb, line 2690
def inspect
  str = ["#<", self.class.to_s, " io_type:"]
  # show type of wrapped IO
  if    @io == $stdout then str << "$stdout"
  elsif @io == $stdin  then str << "$stdin"
  elsif @io == $stderr then str << "$stderr"
  else                      str << @io.class.to_s
  end
  # show IO.path(), if available
  if @io.respond_to?(:path) and (p = @io.path)
    str << " io_path:" << p.inspect
  end
  # show encoding
  str << " encoding:" << @encoding.name
  # show other attributes
  ["lineno", "col_sep", "row_sep", "quote_char"].each do |attr_name|
    if a = __send__(attr_name)
      str << " " << attr_name << ":" << a.inspect
    end
  end
  ["skip_blanks", "liberal_parsing"].each do |attr_name|
    if a = __send__("#{attr_name}?")
      str << " " << attr_name << ":" << a.inspect
    end
  end
  _headers = headers
  str << " headers:" << _headers.inspect if _headers
  str << ">"
  begin
    str.join('')
  rescue  # any encoding error
    str.map do |s|
      e = Encoding::Converter.asciicompat_encoding(s.encoding)
      e ? s.encode(e) : s.force_encoding("ASCII-8BIT")
    end.join('')
  end
end
ioctl(*args) 按一下以切換來源
# File lib/csv.rb, line 2274
def ioctl(*args)
  raise NotImplementedError unless @io.respond_to?(:ioctl)
  @io.ioctl(*args)
end
liberal_parsing? → true 或 false 按一下以切換來源

傳回決定是否要處理非法輸入的數值;用於剖析;請參閱 {Option liberal_parsing}

CSV.new('').liberal_parsing? # => false
# File lib/csv.rb, line 2182
def liberal_parsing?
  parser.liberal_parsing?
end
line → 陣列 按一下以切換來源

傳回最近讀取的列

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

輸出

[1, "foo,0\n"]
[2, "bar,1\n"]
[3, "baz,2\n"]
# File lib/csv.rb, line 2247
def line
  parser.line
end
line_no → 整數 按一下以切換來源

傳回已剖析或產生的列數。

剖析

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

輸出

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

產生

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

輸出

0
1
2
# File lib/csv.rb, line 2223
def lineno
  if @writer
    @writer.lineno
  else
    parser.lineno
  end
end
max_field_size → 整數或 nil 按一下以切換來源

傳回欄位大小的限制;用於剖析;請參閱 {Option max_field_size}

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

自 3.2.3 起。

# File lib/csv.rb, line 2053
def max_field_size
  parser.max_field_size
end
path() 按一下以切換來源
# File lib/csv.rb, line 2279
def path
  @io.path if @io.respond_to?(:path)
end
puts
別名為:<<
quote_char → 字元 按一下以切換來源

傳回編碼的引號字元;用於剖析和寫入;請參閱 {選項 quote_char}

CSV.new('').quote_char # => "\""
# File lib/csv.rb, line 2029
def quote_char
  parser.quote_character
end
read → 陣列或 csv_table 按一下以切換來源

self 形成其餘列為

  • 一個 CSV::Table 物件,如果正在使用標頭。

  • 一個陣列的陣列,否則。

資料來源必須開啟以供讀取。

沒有標頭

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

有標頭

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

如果來源未開啟以供讀取,則會引發例外狀況

string = "foo,0\nbar,1\nbaz,2\n"
csv = CSV.new(string)
csv.close
# Raises IOError (not opened for reading)
csv.read
# File lib/csv.rb, line 2595
def read
  rows = to_a
  if parser.use_headers?
    Table.new(rows, headers: parser.headers)
  else
    rows
  end
end
別名為:readlines
readline
別名為: shift
readlines
別名為:read
return_headers? → true 或 false 按一下以切換來源

傳回決定是否傳回標頭的值;用於剖析;請參閱 {選項 return_headers}

CSV.new('').return_headers? # => false
# File lib/csv.rb, line 2124
def return_headers?
  parser.return_headers?
end
rewind() 按一下以切換來源

倒帶基礎 IO 物件並重設 CSV 的 lineno() 計數器。

# File lib/csv.rb, line 2312
def rewind
  @parser = nil
  @parser_enumerator = nil
  @eof_error = nil
  @writer.rewind if @writer
  @io.rewind
end
row_sep → 字串 按一下以切換來源

傳回編碼的列分隔符號;用於剖析和寫入;請參閱 {選項 row_sep}

CSV.new('').row_sep # => "\n"
# File lib/csv.rb, line 2019
def row_sep
  parser.row_separator
end
shift → 陣列、csv_row 或 nil 按一下以切換來源

傳回下一列資料為

  • 一個陣列,如果未使用標頭。

  • 一個 CSV::Row 物件,如果正在使用標頭。

資料來源必須開啟以供讀取。

沒有標頭

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

有標頭

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

如果來源未開啟以供讀取,則會引發例外狀況

string = "foo,0\nbar,1\nbaz,2\n"
csv = CSV.new(string)
csv.close
# Raises IOError (not opened for reading)
csv.shift
# File lib/csv.rb, line 2668
def shift
  if @eof_error
    eof_error, @eof_error = @eof_error, nil
    raise eof_error
  end
  begin
    parser_enumerator.next
  rescue StopIteration
    nil
  end
end
別名為:getsreadline
skip_blanks? → true 或 false 按一下以切換來源

傳回決定是否忽略空白列的值;用於剖析;請參閱 {選項 skip_blanks}

CSV.new('').skip_blanks? # => false
# File lib/csv.rb, line 2161
def skip_blanks?
  parser.skip_blanks?
end
skip_lines → regexp 或 nil 按一下以切換來源

傳回用於識別註解行的 Regexp;用於剖析;請參閱 {選項 skip_lines}

CSV.new('').skip_lines # => nil
# File lib/csv.rb, line 2063
def skip_lines
  parser.skip_lines
end
stat(*args) 按一下以切換來源
# File lib/csv.rb, line 2283
def stat(*args)
  raise NotImplementedError unless @io.respond_to?(:stat)
  @io.stat(*args)
end
to_i() 按一下以切換來源
# File lib/csv.rb, line 2288
def to_i
  raise NotImplementedError unless @io.respond_to?(:to_i)
  @io.to_i
end
to_io() 按一下以切換來源
# File lib/csv.rb, line 2293
def to_io
  @io.respond_to?(:to_io) ? @io.to_io : @io
end
unconverted_fields? → 物件 按一下以切換來源

傳回值,用於判斷是否提供未轉換的欄位;用於剖析;請參閱 {選項 unconverted_fields}

CSV.new('').unconverted_fields? # => nil
# File lib/csv.rb, line 2096
def unconverted_fields?
  parser.unconverted_fields?
end
write_headers? → true 或 false 按一下以切換來源

傳回值,用於判斷是否撰寫標頭;用於產生;請參閱 {選項 write_headers}

CSV.new('').write_headers? # => nil
# File lib/csv.rb, line 2134
def write_headers?
  @writer_options[:write_headers]
end

私人執行個體方法

build_fields_converter(initial_converters, options) 按一下以切換來源
# File lib/csv.rb, line 2822
def build_fields_converter(initial_converters, options)
  fields_converter = FieldsConverter.new(options)
  normalize_converters(initial_converters).each do |name, converter|
    fields_converter.add_converter(name, &converter)
  end
  fields_converter
end
build_header_fields_converter() 按一下以切換來源
# File lib/csv.rb, line 2804
def build_header_fields_converter
  specific_options = {
    builtin_converters_name: :HeaderConverters,
    accept_nil: true,
  }
  options = @base_fields_converter_options.merge(specific_options)
  build_fields_converter(@initial_header_converters, options)
end
build_parser_fields_converter() 按一下以切換來源
# File lib/csv.rb, line 2792
def build_parser_fields_converter
  specific_options = {
    builtin_converters_name: :Converters,
  }
  options = @base_fields_converter_options.merge(specific_options)
  build_fields_converter(@initial_converters, options)
end
build_writer_fields_converter() 按一下以切換來源
# File lib/csv.rb, line 2817
def build_writer_fields_converter
  build_fields_converter(@initial_write_converters,
                         @write_fields_converter_options)
end
convert_fields(fields, headers = false) 按一下以切換來源

使用 @converters 處理 fields,或在將 headers 傳遞為 true 時使用 @header_converters,傳回轉換後的欄位組。任何將欄位轉換為 String 以外的轉換器都會停止該欄位的轉換管線。這主要是效率捷徑。

# File lib/csv.rb, line 2767
def convert_fields(fields, headers = false)
  if headers
    header_fields_converter.convert(fields, nil, 0)
  else
    parser_fields_converter.convert(fields, @headers, lineno)
  end
end
determine_encoding(encoding, internal_encoding) 按一下以切換來源
# File lib/csv.rb, line 2730
def determine_encoding(encoding, internal_encoding)
  # honor the IO encoding if we can, otherwise default to ASCII-8BIT
  io_encoding = raw_encoding
  return io_encoding if io_encoding

  return Encoding.find(internal_encoding) if internal_encoding

  if encoding
    encoding, = encoding.split(":", 2) if encoding.is_a?(String)
    return Encoding.find(encoding)
  end

  Encoding.default_internal || Encoding.default_external
end
header_fields_converter() 按一下以切換來源
# File lib/csv.rb, line 2800
def header_fields_converter
  @header_fields_converter ||= build_header_fields_converter
end
normalize_converters(converters) 按一下以切換來源
# File lib/csv.rb, line 2745
def normalize_converters(converters)
  converters ||= []
  unless converters.is_a?(Array)
    converters = [converters]
  end
  converters.collect do |converter|
    case converter
    when Proc # custom code block
      [nil, converter]
    else # by name
      [converter, nil]
    end
  end
end
parser() 按一下以切換來源
# File lib/csv.rb, line 2830
def parser
  @parser ||= Parser.new(@io, parser_options)
end
parser_enumerator() 按一下以切換來源
# File lib/csv.rb, line 2839
def parser_enumerator
  @parser_enumerator ||= parser.parse
end
parser_fields_converter() 按一下以切換來源
# File lib/csv.rb, line 2788
def parser_fields_converter
  @parser_fields_converter ||= build_parser_fields_converter
end
parser_options() 按一下以切換來源
# File lib/csv.rb, line 2834
def parser_options
  @parser_options.merge(header_fields_converter: header_fields_converter,
                        fields_converter: parser_fields_converter)
end
raw_encoding() 按一下以切換來源

傳回內部 IO 物件的編碼。

# File lib/csv.rb, line 2778
def raw_encoding
  if @io.respond_to? :internal_encoding
    @io.internal_encoding || @io.external_encoding
  elsif @io.respond_to? :encoding
    @io.encoding
  else
    nil
  end
end
writer() 按一下以切換來源
# File lib/csv.rb, line 2843
def writer
  @writer ||= Writer.new(@io, writer_options)
end
writer_fields_converter() 按一下以切換來源
# File lib/csv.rb, line 2813
def writer_fields_converter
  @writer_fields_converter ||= build_writer_fields_converter
end
writer_options() 按一下以切換來源
# File lib/csv.rb, line 2847
def writer_options
  @writer_options.merge(header_fields_converter: header_fields_converter,
                        fields_converter: writer_fields_converter)
end