類別 CSV
CSV¶ ↑
CSV Data
¶ ↑
CSV(逗號分隔值)資料是表格的文字表示
-
列分隔符號區分表格列。常見的列分隔符號是換行字元
"\n"
。 -
欄分隔符號區分列中的欄位。常見的欄分隔符號是逗號字元
","
。
這個 CSV 字串,列分隔符號為"\n"
,欄分隔符號為","
,有 3 列和 2 行
"foo,0\nbar,1\nbaz,2\n"
儘管名稱為 CSV,CSV 表示法可以使用不同的分隔符號。
有關表格的更多資訊,請參閱維基百科條目「表格(資訊)」,特別是其「簡單表格」部分
類別 CSV¶ ↑
Class
CSV 提供下列方法
-
從字串物件、檔案(透過其檔案路徑)或 IO 物件剖析 CSV 資料。
-
產生 CSV 資料到字串物件。
讓 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#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.new
傳回新的 CSV 物件。 -
方法
CSV.instance
傳回新的或快取的 CSV 物件。 -
方法 CSV() 也會傳回新的或快取的 CSV 物件。
實例方法¶ ↑
CSV 有三組實例方法
-
其本身內部定義的實例方法。
-
由模組
Enumerable
包含的方法。 -
委派給類別
IO
的方法。請參閱下方。
委派的方法¶ ↑
為了方便起見,CSV
物件會委派給類別 IO
中的許多方法。(其中少數在 CSV 中有包裝器「防護程式碼」。)您可以呼叫
-
IO#string
-
IO#truncate
選項¶ ↑
選項的預設值為
DEFAULT_OPTIONS = { # For both parsing and generating. col_sep: ",", row_sep: :auto, quote_char: '"', # For parsing. field_size_limit: nil, converters: nil, unconverted_fields: nil, headers: false, return_headers: false, header_converters: nil, skip_blanks: false, skip_lines: nil, liberal_parsing: false, nil_value: nil, empty_value: "", strip: false, # For generating. write_headers: nil, quote_empty: true, force_quotes: false, write_converters: nil, write_nil_value: nil, write_empty_value: "", }
解析選項¶ ↑
下列是解析選項的詳細說明
-
row_sep
:指定列分隔符號;用於區分列。 -
col_sep
:指定欄分隔符號;用於區分欄位。 -
quote_char
:指定引號字元;用於引用欄位。 -
field_size_limit
:指定允許的最大欄位大小 + 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
。 -
串流僅可用於輸出。
很明顯地,偵測需要一點時間。如果速度很重要,請手動 設定
。另請注意,如果要使用此功能,應在 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_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
,會使用目前的 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 相同,但
-
轉換器只套用於標題列。
-
內建的標題轉換器為
:downcase
和:symbol
。
此區段假設之前已執行
str = <<-EOT Name,Value foo,0 bar,1 baz,2 EOT # With no header converter table = CSV.parse(str, headers: true) table.headers # => ["Name", "Value"]
值可以是標題轉換器名稱(請參閱 儲存的轉換器)
table = CSV.parse(str, headers: true, header_converters: :downcase) table.headers # => ["name", "value"]
值可以是轉換器清單(請參閱 轉換器清單)
header_converters = [:downcase, :symbol] table = CSV.parse(str, headers: true, header_converters: header_converters) table.headers # => [:name, :value]
值可以是 Proc 自訂轉換器(請參閱 自訂標題轉換器)
upcase_converter = proc {|field| field.upcase } table = CSV.parse(str, headers: true, header_converters: upcase_converter) table.headers # => ["NAME", "VALUE"]
另請參閱 自訂標題轉換器
選項 skip_blanks
¶ ↑
指定布林值,用於判斷輸入中的空白列是否會被忽略;包含欄位分隔符號的列不會被視為空白。
預設值
CSV::DEFAULT_OPTIONS.fetch(:skip_blanks) # => false
另請參閱選項 skiplines。
本節範例
str = <<-EOT foo,0 bar,1 baz,2 , EOT
使用預設值 false
ary = CSV.parse(str) ary # => [["foo", "0"], [], ["bar", "1"], ["baz", "2"], [], [nil, nil]]
使用 true
ary = CSV.parse(str, skip_blanks: true) ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"], [nil, nil]]
使用真值
ary = CSV.parse(str, skip_blanks: :foo) ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"], [nil, nil]]
選項 skip_lines
¶ ↑
指定物件,用於識別輸入中要忽略的註解列
-
如果為 Regexp,則忽略與之相符的列。
-
如果為字串,則將其轉換為 Regexp,忽略與之相符的列。
-
如果為
nil
,則沒有列會被視為註解。
預設值
CSV::DEFAULT_OPTIONS.fetch(:skip_lines) # => nil
本節範例
str = <<-EOT # Comment foo,0 bar,1 baz,2 # Another comment EOT str # => "# Comment\nfoo,0\nbar,1\nbaz,2\n# Another comment\n"
使用預設值 nil
ary = CSV.parse(str) ary # => [["# Comment"], ["foo", "0"], ["bar", "1"], ["baz", "2"], ["# Another comment"]]
使用 Regexp
ary = CSV.parse(str, skip_lines: /^#/) ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
使用字串
ary = CSV.parse(str, skip_lines: '#') ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
如果給定的物件不是 Regexp、字串或 nil
,則會引發例外狀況
# Raises ArgumentError (:skip_lines has to respond to #match: 0) CSV.parse(str, skip_lines: 0)
選項 strip
¶ ↑
指定布林值,用於判斷是否從每個輸入欄位移除空白。
預設值
CSV::DEFAULT_OPTIONS.fetch(:strip) # => false
預設值為 false
ary = CSV.parse_line(' a , b ') ary # => [" a ", " b "]
值為 true
ary = CSV.parse_line(' a , b ', strip: true) ary # => ["a", "b"]
選項 liberal_parsing
¶ ↑
指定布林值或雜湊值,用於判斷 CSV
是否會嘗試剖析不符合 RFC 4180 的輸入,例如未加引號欄位中的雙引號。
預設值
CSV::DEFAULT_OPTIONS.fetch(:liberal_parsing) # => false
以下兩個範例
str = 'is,this "three, or four",fields'
沒有 liberal_parsing
# Raises CSV::MalformedCSVError (Illegal quoting in str 1.) CSV.parse_line(str)
有 liberal_parsing
ary = CSV.parse_line(str, liberal_parsing: true) ary # => ["is", "this \"three", " or four\"", "fields"]
使用 backslash_quote
子選項剖析使用反斜線跳脫雙引號字元的數值。這會讓剖析器將 \"
視為 ""
。
以下兩個範例
str = 'Show,"Harry \"Handcuff\" Houdini, the one and only","Tampa Theater"'
有 liberal_parsing
,但沒有 backslash_quote
子選項
# Incorrect interpretation of backslash; incorrectly interprets the quoted comma as a field separator. ary = CSV.parse_line(str, liberal_parsing: true) ary # => ["Show", "\"Harry \\\"Handcuff\\\" Houdini", " the one and only\"", "Tampa Theater"] puts ary[1] # => "Harry \"Handcuff\" Houdini
有 liberal_parsing
及其 backslash_quote
子選項
ary = CSV.parse_line(str, liberal_parsing: { backslash_quote: true }) ary # => ["Show", "Harry \"Handcuff\" Houdini, the one and only", "Tampa Theater"] puts ary[1] # => Harry "Handcuff" Houdini, the one and only
選項 nil_value
¶ ↑
指定要替換每個空值(無文字)欄位的物件。
預設值
CSV::DEFAULT_OPTIONS.fetch(:nil_value) # => nil
使用預設值 nil
CSV.parse_line('a,,b,,c') # => ["a", nil, "b", nil, "c"]
使用不同的物件
CSV.parse_line('a,,b,,c', nil_value: 0) # => ["a", 0, "b", 0, "c"]
選項 empty_value
¶ ↑
指定要替換每個具有空字串的欄位的物件。
預設值
CSV::DEFAULT_OPTIONS.fetch(:empty_value) # => "" (empty string)
使用預設值 ""
CSV.parse_line('a,"",b,"",c') # => ["a", "", "b", "", "c"]
使用不同的物件
CSV.parse_line('a,"",b,"",c', empty_value: 'x') # => ["a", "x", "b", "x", "c"]
產生選項¶ ↑
產生選項,如下詳細說明,包括
-
row_sep
:指定列分隔符號;用於區分列。 -
col_sep
:指定欄分隔符號;用於區分欄位。 -
quote_char
:指定引號字元;用於引用欄位。 -
write_headers
:指定是否要寫入標題。 -
force_quotes
:指定是否要對每個輸出欄位加上引號。 -
quote_empty
:指定是否要對每個空輸出欄位加上引號。 -
write_converters
:指定寫入時要使用的欄位轉換器。 -
write_nil_value
:指定要替換每個nil
值欄位的物件。 -
write_empty_value
:指定要替換每個空欄位的物件。
選項 row_sep
¶ ↑
指定列分隔符號,為字串或符號 :auto
(請參閱下方),用於解析和產生。
預設值
CSV::DEFAULT_OPTIONS.fetch(:row_sep) # => :auto
當 row_sep
為字串時,該字串會成為列分隔符號。String
會在使用前轉碼成資料的 Encoding
。
使用 "\n"
row_sep = "\n" str = CSV.generate(row_sep: row_sep) do |csv| csv << [:foo, 0] csv << [:bar, 1] csv << [:baz, 2] end str # => "foo,0\nbar,1\nbaz,2\n" ary = CSV.parse(str) ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
使用 |
(直線)
row_sep = '|' str = CSV.generate(row_sep: row_sep) do |csv| csv << [:foo, 0] csv << [:bar, 1] csv << [:baz, 2] end str # => "foo,0|bar,1|baz,2|" ary = CSV.parse(str, row_sep: row_sep) ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
使用 --
(兩個連字號)
row_sep = '--' str = CSV.generate(row_sep: row_sep) do |csv| csv << [:foo, 0] csv << [:bar, 1] csv << [:baz, 2] end str # => "foo,0--bar,1--baz,2--" ary = CSV.parse(str, row_sep: row_sep) ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
使用 ''
(空字串)
row_sep = '' str = CSV.generate(row_sep: row_sep) do |csv| csv << [:foo, 0] csv << [:bar, 1] csv << [:baz, 2] end str # => "foo,0bar,1baz,2" ary = CSV.parse(str, row_sep: row_sep) ary # => [["foo", "0bar", "1baz", "2"]]
當 row_sep
是符號 :auto
(預設值)時,產生會使用 "\n"
作為列分隔符號
str = CSV.generate do |csv| csv << [:foo, 0] csv << [:bar, 1] csv << [:baz, 2] end str # => "foo,0\nbar,1\nbaz,2\n"
另一方面,剖析會呼叫列分隔符號的自動偵測。
自動偵測會讀取資料中的前段,尋找下一個 \r\n
、\n
或 \r
序列。即使序列出現在引號欄位中,也會選取該序列,假設您在那裡會有相同的行尾。
範例
str = CSV.generate do |csv| csv << [:foo, 0] csv << [:bar, 1] csv << [:baz, 2] end str # => "foo,0\nbar,1\nbaz,2\n" ary = CSV.parse(str) ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
如果下列任一條件為真,就會使用預設的 $INPUT_RECORD_SEPARATOR
($/
)
-
找不到任何這些序列。
-
Data
是ARGF
、STDIN
、STDOUT
或STDERR
。 -
串流僅可用於輸出。
很明顯地,偵測需要一點時間。如果速度很重要,請手動 設定
。另請注意,如果要使用此功能,應在 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
參數中指定轉換器,以進行解析或產生
-
選項
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
:將每個嵌入字串的日期時間轉換為真正的日期時間
。這個範例會建立一個轉換器程序,然後儲存它
strip_converter = proc {|field| field.strip } CSV::Converters[:strip] = strip_converter
然後,解析方法呼叫可以透過名稱 :strip
參照轉換器。
string = " foo , 0 \n bar , 1 \n baz , 2 \n" array = CSV.parse(string, converters: :strip) array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
標頭轉換器的儲存結構是雜湊 CSV::HeaderConverters
,其工作方式相同。它也有內建的轉換器程序
-
:downcase
:將每個標頭轉換為小寫。 -
:symbol
:將每個標頭轉換為符號。
沒有這樣的儲存結構來寫入標頭。
為了讓解析方法存取非主 Ractor 中的儲存轉換器,必須先讓儲存結構可共用。因此,必須在使用儲存在這些結構中的轉換器的 Ractor 建立之前,呼叫 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
所做的。)
使用欄位轉換器有下列三種方式。
-
使用選項 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
搭配單例解析方法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。剖析器會在 IO
或 String
物件的 編碼
中執行,這些物件會從中讀取或寫入資料。您的資料永遠不會被轉碼(除非您要求 Ruby 為您轉碼),而且會直接在它所在的 編碼
中被剖析。因此,CSV
會傳回陣列或列,這些陣列或列中的字串會使用您的資料的 編碼
。這是透過將剖析器本身轉碼成您的 編碼
來完成的。
當然,為了達成這個多編碼支援,必須進行一些轉碼。例如,:col_sep
、:row_sep
和 :quote_char
必須被轉碼,以符合您的資料。希望這會讓整個程序感覺起來很透明,因為 CSV 的預設值應該會神奇地適用於您的資料。不過,您可以在目標 編碼
中手動設定這些值,以避免轉換。
另外,值得注意的是,雖然 CSV 的所有核心剖析器現在都與 編碼
無關,但有些功能並非如此。例如,內建轉換器會嘗試在進行轉換之前將資料轉碼為 UTF-8。同樣地,您可以提供自訂轉換器,這些轉換器會知道您的編碼,以避免這個轉換。對於我來說,要支援 Ruby 的所有編碼中的原生轉換實在太困難了。
無論如何,這方面的實務很簡單:確保傳遞給 IO
和 String
物件的 CSV
已設定適當的 Encoding
,一切應該都能正常運作。允許您開啟 IO
物件(CSV::foreach()
、CSV::open()
、CSV::read()
和 CSV::readlines()
)的 CSV
方法允許您指定 Encoding
。
當使用與 ASCII 不相容的 Encoding
將 CSV
產生到 String
時,會出現一個小例外。沒有現有的資料可供 CSV
用來準備自己,因此您可能需要手動指定大多數情況下所需的 Encoding
。不過,當使用 CSV::generate_line()
或 Array#to_csv() 時,它會嘗試使用輸出列中的欄位來猜測。
我會在方法的說明文件中指出任何其他 Encoding
問題,因為它們會出現。
這已經過我最大的能力測試,使用 Ruby 附帶的所有非「虛擬」編碼。但是,它是全新的程式碼,可能有一些錯誤。請隨時 回報 您發現的任何問題。
常數
- ConverterEncoding
所有轉換器使用的編碼。
- 轉換器
包含內建欄位轉換器的名稱和程序的雜湊。請參閱 內建欄位轉換器。
這個雜湊故意不凍結,並且可以用自訂欄位轉換器來擴充。請參閱 自訂欄位轉換器。
- DEFAULT_OPTIONS
方法選項的預設值。
- DateMatcher
- DateTimeMatcher
- FieldInfo
一個
FieldInfo
Struct
包含從其讀取資料來源中欄位的詳細資訊。CSV
會將這個Struct
傳遞給根據欄位結構做出決定的某些區塊。請參閱CSV.convert_fields()
以取得範例。索引
-
欄位在其列中的以零為基準的索引。
列
-
此列來自資料來源的列。
標頭
-
欄位的標頭(如果可用)。
已引號?
-
True 或 false,表示原始值是否已引號。
- HeaderConverters
包含內建標頭轉換器的名稱和 Procs 的 Hash。請參閱 內建標頭轉換器。
此 Hash 故意保留未凍結,並可以使用自訂欄位轉換器進行擴充。請參閱 自訂標頭轉換器。
- 版本
已安裝函式庫的版本。
屬性
:call-seq
csv.encoding -> encoding
傳回用於剖析和產生的編碼;請參閱 字元編碼 (M17n 或多語言化)
CSV.new('').encoding # => #<Encoding:UTF-8>
公開類別方法
-
從來源 (字串、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_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"
沒有標頭的 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_io
或 out_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
使用從來源 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
選項,您可以使用此選項指定從path
或io
讀取的資料的編碼
。除非您的資料採用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
-
如果提供了參數
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
傳回使用指定的 options
從 ary
產生 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
傳回使用指定的 options
從 ary
產生 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
建立或擷取快取的 CSV 物件。有關引數和選項,請參閱 CSV.new
。
此 API 不支援 Ractor。
如果未提供區塊,則傳回 CSV 物件。
第一次呼叫 instance
會建立並快取 CSV 物件
s0 = 's0' csv0 = CSV.instance(s0) csv0.class # => CSV
使用相同的 string
或 io
再次呼叫 instance
會擷取相同的快取物件
csv1 = CSV.instance(s0) csv1.class # => CSV csv1.equal?(csv0) # => true # Same CSV object
使用不同的 string
或 io
再次呼叫 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
傳回使用 string
或 io
和指定的 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
可能的選項元素
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
選項,您可以使用此選項指定從path
或io
讀取的資料的編碼
。除非您的資料採用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
使用指定的 options
分析 string
或 io
。
-
引數
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
傳回使用指定的 options
分析 string
或 io
的第一列所建立的資料。
-
引數
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
使用指定的 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
別名為 CSV.read
。
# File lib/csv.rb, line 1837 def readlines(path, **options) read(path, **options) end
使用 source
、options
和某些預設選項呼叫 CSV.read
-
headers
:true
-
converters
::numeric
-
header_converters
::symbol
傳回 CSV::Table
物件。
範例
string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" path = 't.csv' File.write(path, string) CSV.table(path) # => #<CSV::Table mode:col_or_row row_count:4>
# File lib/csv.rb, line 1856 def table(path, **options) default_options = { headers: true, converters: :numeric, header_converters: :symbol, } options = default_options.merge(options) read(path, **options) end
公開實體方法
將列新增至 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
# File lib/csv.rb, line 2261 def binmode? if @io.respond_to?(:binmode?) @io.binmode? else false end end
傳回編碼的欄位分隔符號;用於剖析和寫入;請參閱 {選項 col_sep
}
CSV.new('').col_sep # => ","
# File lib/csv.rb, line 2009 def col_sep parser.column_separator end
-
沒有區塊時,安裝欄位轉換器(一個程序)。
-
有區塊時,定義並安裝自訂欄位轉換器。
-
傳回已安裝欄位轉換器的陣列。
-
如果提供引數
converter_name
,應為現有欄位轉換器的名稱。
請參閱 欄位轉換器。
沒有區塊時,安裝欄位轉換器
csv = CSV.new('') csv.convert(:integer) csv.convert(:float) csv.convert(:date) csv.converters # => [:integer, :float, :date]
如果提供區塊,則會針對每個欄位呼叫該區塊
-
引數
field
是欄位值。 -
引數
field_info
是CSV::FieldInfo
物件,其中包含欄位的詳細資料。
此處的範例假設先前執行
string = "foo,0\nbar,1\nbaz,2\n" path = 't.csv' File.write(path, string)
提供區塊的範例
csv = CSV.open(path) csv.convert {|field, field_info| p [field, field_info]; field.upcase } csv.read # => [["FOO", "0"], ["BAR", "1"], ["BAZ", "2"]]
輸出
["foo", #<struct CSV::FieldInfo index=0, line=1, header=nil>] ["0", #<struct CSV::FieldInfo index=1, line=1, header=nil>] ["bar", #<struct CSV::FieldInfo index=0, line=2, header=nil>] ["1", #<struct CSV::FieldInfo index=1, line=2, header=nil>] ["baz", #<struct CSV::FieldInfo index=0, line=3, header=nil>] ["2", #<struct CSV::FieldInfo index=1, line=3, header=nil>]
區塊不必傳回字串物件
csv = CSV.open(path) csv.convert {|field, field_info| field.to_sym } csv.read # => [[:foo, :"0"], [:bar, :"1"], [:baz, :"2"]]
如果提供 converter_name
,則不會呼叫區塊
csv = CSV.open(path) csv.convert(:integer) {|field, field_info| fail 'Cannot happen' } csv.read # => [["foo", 0], ["bar", 1], ["baz", 2]]
如果 converter_name
不是內建欄位轉換器的名稱,則會引發解析時間例外狀況
csv = CSV.open(path) csv.convert(:nosuch) => [nil] # Raises NoMethodError (undefined method `arity' for nil:NilClass) csv.read
# File lib/csv.rb, line 2443 def convert(name = nil, &converter) parser_fields_converter.add_converter(name, &converter) end
傳回包含欄位轉換器的陣列;請參閱 欄位轉換器
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
使用每個後續列呼叫區塊。資料來源必須開啟以供讀取。
沒有標頭
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
# 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
傳回欄位大小的限制;用於解析;請參閱 {選項 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
# File lib/csv.rb, line 2269 def flock(*args) raise NotImplementedError unless @io.respond_to?(:flock) @io.flock(*args) end
傳回決定是否要引用所有輸出欄位的數值;用於產生;請參閱 {Option force_quotes
}
CSV.new('').force_quotes? # => false
# File lib/csv.rb, line 2172 def force_quotes? @writer_options[:force_quotes] end
區塊不必傳回字串物件
csv = CSV.open(path, headers: true) csv.header_convert {|header, field_info| header.to_sym } table = csv.read table.headers # => [:Name, :Value]
如果提供 converter_name
,則不會呼叫區塊
csv = CSV.open(path, headers: true) csv.header_convert(:downcase) {|header, field_info| fail 'Cannot happen' } table = csv.read table.headers # => ["name", "value"]
如果 converter_name
不是內建欄位轉換器的名稱,則會引發解析時間例外狀況
csv = CSV.open(path, headers: true) csv.header_convert(:nosuch) # Raises NoMethodError (undefined method `arity' for nil:NilClass) csv.read
# File lib/csv.rb, line 2509 def header_convert(name = nil, &converter) header_fields_converter.add_converter(name, &converter) end
傳回包含標頭轉換器的陣列;用於剖析;請參閱 標頭轉換器
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
如果要讀取的下一個列是標頭列,則傳回 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
傳回決定是否使用標頭的數值;用於剖析;請參閱 {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
傳回顯示 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
# File lib/csv.rb, line 2274 def ioctl(*args) raise NotImplementedError unless @io.respond_to?(:ioctl) @io.ioctl(*args) end
傳回決定是否要處理非法輸入的數值;用於剖析;請參閱 {Option liberal_parsing
}
CSV.new('').liberal_parsing? # => false
# File lib/csv.rb, line 2182 def liberal_parsing? parser.liberal_parsing? end
傳回最近讀取的列
string = "foo,0\nbar,1\nbaz,2\n" path = 't.csv' File.write(path, string) CSV.open(path) do |csv| csv.each do |row| p [csv.lineno, csv.line] end end
輸出
[1, "foo,0\n"] [2, "bar,1\n"] [3, "baz,2\n"]
# File lib/csv.rb, line 2247 def line parser.line end
傳回已剖析或產生的列數。
剖析
string = "foo,0\nbar,1\nbaz,2\n" path = 't.csv' File.write(path, string) CSV.open(path) do |csv| csv.each do |row| p [csv.lineno, 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
傳回欄位大小的限制;用於剖析;請參閱 {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
# File lib/csv.rb, line 2279 def path @io.path if @io.respond_to?(:path) end
傳回編碼的引號字元;用於剖析和寫入;請參閱 {選項 quote_char
}
CSV.new('').quote_char # => "\""
# File lib/csv.rb, line 2029 def quote_char parser.quote_character end
從 self
形成其餘列為
-
一個
CSV::Table
物件,如果正在使用標頭。 -
一個陣列的陣列,否則。
資料來源必須開啟以供讀取。
沒有標頭
string = "foo,0\nbar,1\nbaz,2\n" path = 't.csv' File.write(path, string) csv = CSV.open(path) csv.read # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
有標頭
string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" path = 't.csv' File.write(path, string) csv = CSV.open(path, headers: true) csv.read # => #<CSV::Table mode:col_or_row row_count:4>
如果來源未開啟以供讀取,則會引發例外狀況
string = "foo,0\nbar,1\nbaz,2\n" csv = CSV.new(string) csv.close # Raises IOError (not opened for reading) csv.read
# File lib/csv.rb, line 2595 def read rows = to_a if parser.use_headers? Table.new(rows, headers: parser.headers) else rows end end
傳回決定是否傳回標頭的值;用於剖析;請參閱 {選項 return_headers
}
CSV.new('').return_headers? # => false
# File lib/csv.rb, line 2124 def return_headers? parser.return_headers? end
倒帶基礎 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
}
CSV.new('').row_sep # => "\n"
# File lib/csv.rb, line 2019 def row_sep parser.row_separator end
傳回下一列資料為
-
一個陣列,如果未使用標頭。
-
一個
CSV::Row
物件,如果正在使用標頭。
資料來源必須開啟以供讀取。
沒有標頭
string = "foo,0\nbar,1\nbaz,2\n" csv = CSV.new(string) csv.shift # => ["foo", "0"] csv.shift # => ["bar", "1"] csv.shift # => ["baz", "2"] csv.shift # => nil
有標頭
string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" csv = CSV.new(string, headers: true) csv.shift # => #<CSV::Row "Name":"foo" "Value":"0"> csv.shift # => #<CSV::Row "Name":"bar" "Value":"1"> csv.shift # => #<CSV::Row "Name":"baz" "Value":"2"> csv.shift # => nil
如果來源未開啟以供讀取,則會引發例外狀況
string = "foo,0\nbar,1\nbaz,2\n" csv = CSV.new(string) csv.close # Raises IOError (not opened for reading) csv.shift
# File lib/csv.rb, line 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
傳回決定是否忽略空白列的值;用於剖析;請參閱 {選項 skip_blanks
}
CSV.new('').skip_blanks? # => false
# File lib/csv.rb, line 2161 def skip_blanks? parser.skip_blanks? end
傳回用於識別註解行的 Regexp;用於剖析;請參閱 {選項 skip_lines
}
CSV.new('').skip_lines # => nil
# File lib/csv.rb, line 2063 def skip_lines parser.skip_lines end
# File lib/csv.rb, line 2283 def stat(*args) raise NotImplementedError unless @io.respond_to?(:stat) @io.stat(*args) end
# File lib/csv.rb, line 2288 def to_i raise NotImplementedError unless @io.respond_to?(:to_i) @io.to_i end
# File lib/csv.rb, line 2293 def to_io @io.respond_to?(:to_io) ? @io.to_io : @io end
傳回值,用於判斷是否提供未轉換的欄位;用於剖析;請參閱 {選項 unconverted_fields
}
CSV.new('').unconverted_fields? # => nil
# File lib/csv.rb, line 2096 def unconverted_fields? parser.unconverted_fields? end
傳回值,用於判斷是否撰寫標頭;用於產生;請參閱 {選項 write_headers
}
CSV.new('').write_headers? # => nil
# File lib/csv.rb, line 2134 def write_headers? @writer_options[:write_headers] end
私人執行個體方法
# 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
# 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
# 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
# File lib/csv.rb, line 2817 def build_writer_fields_converter build_fields_converter(@initial_write_converters, @write_fields_converter_options) end
使用 @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
# 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
# File lib/csv.rb, line 2800 def header_fields_converter @header_fields_converter ||= build_header_fields_converter end
# 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
# File lib/csv.rb, line 2830 def parser @parser ||= Parser.new(@io, parser_options) end
# File lib/csv.rb, line 2839 def parser_enumerator @parser_enumerator ||= parser.parse end
# File lib/csv.rb, line 2788 def parser_fields_converter @parser_fields_converter ||= build_parser_fields_converter end
# File lib/csv.rb, line 2834 def parser_options @parser_options.merge(header_fields_converter: header_fields_converter, fields_converter: parser_fields_converter) end
傳回內部 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
# File lib/csv.rb, line 2843 def writer @writer ||= Writer.new(@io, writer_options) end
# File lib/csv.rb, line 2813 def writer_fields_converter @writer_fields_converter ||= build_writer_fields_converter end
# File lib/csv.rb, line 2847 def writer_options @writer_options.merge(header_fields_converter: header_fields_converter, fields_converter: writer_fields_converter) end