本文簡要介紹ruby語言中 CSV類
的用法。
CSV
CSV(逗號分隔變量)數據是表格的文本表示:
-
row
separator
分隔表行。常見的行分隔符是換行符"\n"
。 -
column
separator
分隔一行中的字段。常見的列分隔符是逗號字符","
。
此 CSV 字符串帶有行分隔符 "\n"
和列分隔符 ","
,具有三行兩列:
"foo,0\nbar,1\nbaz,2\n"
盡管名稱為 CSV,但 CSV 表示可以使用不同的分隔符。
有關表格的更多信息,請參閱 Wikipedia 文章“Table (information)”,尤其是其部分“Simple table”
CSV 類
Class
CSV 提供以下方法:
-
從字符串對象、文件(通過其文件路徑)或 IO 對象解析 CSV 數據。
-
將 CSV 數據生成到 String 對象。
要使 CSV 可用:
require 'csv'
這裏的所有示例都假設這已經完成。
保持簡單
一個 CSV 對象有幾十個實例方法,它們提供對解析和生成 CSV 數據的細粒度控製。但是,對於許多需求,更簡單的方法就可以了。
本節總結了 CSV 中的單例方法,這些方法允許您在不顯式創建 CSV 對象的情況下進行解析和生成。有關詳細信息,請點擊鏈接。
簡單解析
解析方法通常返回以下之一:
-
一個字符串數組:
-
外部數組是整個“table”。
-
每個內部數組是一行。
-
每個字符串都是一個字段。
-
-
一個
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"
“Filtering” CSV
方法 CSV.filter
為 CSV 數據提供了一個 Unix-style 過濾器。處理輸入數據以形成輸出數據:
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 中有包裝 “guard code”。)您可以調用:
-
IO#字符串
-
IO#截斷
選項
選項的默認值為:
DEFAULT_OPTIONS = {
# For both parsing and generating.
col_sep: ",",
row_sep: :auto,
quote_char: '"',
# For parsing.
field_size_limit: nil,
converters: nil,
unconverted_fields: nil,
headers: false,
return_headers: false,
header_converters: nil,
skip_blanks: false,
skip_lines: nil,
liberal_parsing: false,
nil_value: nil,
empty_value: "",
strip: false,
# For generating.
write_headers: nil,
quote_empty: true,
force_quotes: false,
write_converters: nil,
write_nil_value: nil,
write_empty_value: "",
}
解析選項
下麵詳細說明的解析選項包括:
-
row_sep
:指定行分隔符;用於分隔行。 -
col_sep
:指定列分隔符;用於分隔字段。 -
quote_char
:指定引號字符;用於引用字段。 -
field_size_limit
:指定允許的最大字段大小。 -
converters
:指定要使用的字段轉換器。 -
unconverted_fields
:指定未轉換的字段是否可用。 -
headers
:指定數據是否包含標頭,或指定標頭本身。 -
return_headers
:指定是否要返回標頭。 -
header_converters
:指定要使用的標頭轉換器。 -
skip_blanks
:指定是否忽略空白行。 -
skip_lines
:指定如何識別注釋行。 -
strip
:指定是否要從字段中去除前導和尾隨空格。這必須與col_sep
兼容;如果不是,則會引發ArgumentError
異常。 -
liberal_parsing
:指定 CSV 是否應嘗試解析不合規的數據。 -
nil_value
:指定要替換每個空 (no-text) 字段的對象。 -
empty_value
:指定要替換每個空字段的對象。
選項row_sep
指定行分隔符、字符串或符號:auto
(見下文),用於解析和生成。
默認值:
CSV::DEFAULT_OPTIONS.fetch(:row_sep) # => :auto
當row_sep
是字符串時,該字符串將成為行分隔符。 String
將在使用前轉碼為數據的 Encoding
。
使用 "\n"
:
row_sep = "\n"
str = CSV.generate(row_sep: row_sep) do |csv|
csv << [:foo, 0]
csv << [:bar, 1]
csv << [:baz, 2]
end
str # => "foo,0\nbar,1\nbaz,2\n"
ary = CSV.parse(str)
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
使用|
(管道):
row_sep = '|'
str = CSV.generate(row_sep: row_sep) do |csv|
csv << [:foo, 0]
csv << [:bar, 1]
csv << [:baz, 2]
end
str # => "foo,0|bar,1|baz,2|"
ary = CSV.parse(str, row_sep: row_sep)
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
使用--
(兩個連字符):
row_sep = '--'
str = CSV.generate(row_sep: row_sep) do |csv|
csv << [:foo, 0]
csv << [:bar, 1]
csv << [:baz, 2]
end
str # => "foo,0--bar,1--baz,2--"
ary = CSV.parse(str, row_sep: row_sep)
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
使用''
(空字符串):
row_sep = ''
str = CSV.generate(row_sep: row_sep) do |csv|
csv << [:foo, 0]
csv << [:bar, 1]
csv << [:baz, 2]
end
str # => "foo,0bar,1baz,2"
ary = CSV.parse(str, row_sep: row_sep)
ary # => [["foo", "0bar", "1baz", "2"]]
當row_sep
是符號:auto
(默認)時,生成使用"\n"
作為行分隔符:
str = CSV.generate do |csv|
csv << [:foo, 0]
csv << [:bar, 1]
csv << [:baz, 2]
end
str # => "foo,0\nbar,1\nbaz,2\n"
另一方麵,解析會調用行分隔符的自動發現。
自動發現會提前讀取數據,查找下一個 \r\n
、 \n
或 \r
序列。即使序列出現在帶引號的字段中,也會選擇該序列,假設在那裏有相同的行結尾。
例子:
str = CSV.generate do |csv|
csv << [:foo, 0]
csv << [:bar, 1]
csv << [:baz, 2]
end
str # => "foo,0\nbar,1\nbaz,2\n"
ary = CSV.parse(str)
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
如果滿足以下任一條件,則使用默認 $INPUT_RECORD_SEPARATOR
( $/
):
-
沒有找到這些序列。
-
數據為
ARGF
、STDIN
、STDOUT
或STDERR
。 -
該流僅可用於輸出。
顯然,發現需要一點時間。如果速度很重要,請手動 Set
。另請注意, IO
對象應在 Windows 上以二進製模式打開,如果此函數將用於 line-ending 翻譯可能會導致將文檔位置重置為預讀之前的位置時出現問題。
如果給定值不是String-convertible,則引發異常:
row_sep = BasicObject.new
# Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
CSV.generate(ary, row_sep: row_sep)
# Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
CSV.parse(str, row_sep: row_sep)
選項col_sep
指定用於解析和生成的字符串字段分隔符。 String 在使用前會被轉碼為數據的 Encoding。
默認值:
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)
如果給定值不是String-convertible,則引發異常:
col_sep = BasicObject.new
# Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
CSV.generate(line, col_sep: col_sep)
# Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
CSV.parse(str, col_sep: col_sep)
選項quote_char
指定用於在解析和生成中引用字段的字符(長度為 1 的字符串)。這個 String
會在使用前轉碼成數據的Encoding。
默認值:
CSV::DEFAULT_OPTIONS.fetch(:quote_char) # => "\"" (double quote)
這對於錯誤地使用 '
(single-quote) 而不是正確的 "
(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"]]
使用'
(single-quote):
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
執行任何轉換之前在源數據中找到的字段值。
When option unconverted_fields
is true
, each returned row (Array or CSV::Row) has an added method, unconverted_fields
, that returns the unconverted field values:
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">
如果設置為 Array,則 Array 元素被視為標題:
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">
如果設置為 String str
,則使用當前 options
調用方法 CSV::parse_line(str, options)
,並將返回的 Array 視為標頭:
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
函數與選項轉換器相同,不同之處在於:
-
轉換器僅適用於標題行。
-
內置的標頭轉換器是
: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
另請參見選項跳過線。
對於本節中的示例:
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
指定用於識別輸入中要忽略的注釋行的對象:
-
如果是正則表達式,則忽略與其匹配的行。
-
如果是字符串,則將其轉換為正則表達式,忽略與其匹配的行。
-
如果
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"]]
使用正則表達式:
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、String 或 nil
,則引發異常:
# Raises ArgumentError (:skip_lines has to respond to #match: 0)
CSV.parse(str, skip_lines: 0)
選項strip
指定確定是否從每個輸入字段中去除空格的布爾值。
默認值:
CSV::DEFAULT_OPTIONS.fetch(:strip) # => false
使用默認值 false
:
ary = CSV.parse_line(' a , b ')
ary # => [" a ", " b "]
使用值 true
:
ary = CSV.parse_line(' a , b ', strip: true)
ary # => ["a", "b"]
選項liberal_parsing
指定確定 CSV
是否將嘗試解析不符合 RFC 4180 的輸入的布爾值,例如未引用字段中的雙引號。
默認值:
CSV::DEFAULT_OPTIONS.fetch(:liberal_parsing) # => false
對於本節中的示例:
str = 'is,this "three, or four",fields'
沒有 liberal_parsing
:
# Raises CSV::MalformedCSVError (Illegal quoting in str 1.)
CSV.parse_line(str)
使用 liberal_parsing
:
ary = CSV.parse_line(str, liberal_parsing: true)
ary # => ["is", "this \"three", " or four\"", "fields"]
選項nil_value
指定要替換每個空 (no-text) 字段的對象。
默認值:
CSV::DEFAULT_OPTIONS.fetch(:nil_value) # => nil
使用默認值 nil
:
CSV.parse_line('a,,b,,c') # => ["a", nil, "b", nil, "c"]
使用不同的對象:
CSV.parse_line('a,,b,,c', nil_value: 0) # => ["a", 0, "b", 0, "c"]
選項empty_value
指定要替換具有空字符串的每個字段的對象。
默認值:
CSV::DEFAULT_OPTIONS.fetch(:empty_value) # => "" (empty string)
使用默認值 ""
:
CSV.parse_line('a,"",b,"",c') # => ["a", "", "b", "", "c"]
使用不同的對象:
CSV.parse_line('a,"",b,"",c', empty_value: 'x') # => ["a", "x", "b", "x", "c"]
生成選項
下麵詳細說明的生成選項包括:
-
row_sep
:指定行分隔符;用於分隔行。 -
col_sep
:指定列分隔符;用於分隔字段。 -
quote_char
:指定引號字符;用於引用字段。 -
write_headers
:指定是否要寫入標頭。 -
force_quotes
:指定是否要引用每個輸出字段。 -
quote_empty
:指定是否要引用每個空輸出字段。 -
write_converters
:指定要在寫作中使用的字段轉換器。 -
write_nil_value
:指定要替換每個nil
值字段的對象。 -
write_empty_value
:指定要替換每個空字段的對象。
選項row_sep
指定行分隔符、字符串或符號:auto
(見下文),用於解析和生成。
默認值:
CSV::DEFAULT_OPTIONS.fetch(:row_sep) # => :auto
當row_sep
是字符串時,該字符串將成為行分隔符。 String
將在使用前轉碼為數據的 Encoding
。
使用 "\n"
:
row_sep = "\n"
str = CSV.generate(row_sep: row_sep) do |csv|
csv << [:foo, 0]
csv << [:bar, 1]
csv << [:baz, 2]
end
str # => "foo,0\nbar,1\nbaz,2\n"
ary = CSV.parse(str)
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
使用|
(管道):
row_sep = '|'
str = CSV.generate(row_sep: row_sep) do |csv|
csv << [:foo, 0]
csv << [:bar, 1]
csv << [:baz, 2]
end
str # => "foo,0|bar,1|baz,2|"
ary = CSV.parse(str, row_sep: row_sep)
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
使用--
(兩個連字符):
row_sep = '--'
str = CSV.generate(row_sep: row_sep) do |csv|
csv << [:foo, 0]
csv << [:bar, 1]
csv << [:baz, 2]
end
str # => "foo,0--bar,1--baz,2--"
ary = CSV.parse(str, row_sep: row_sep)
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
使用''
(空字符串):
row_sep = ''
str = CSV.generate(row_sep: row_sep) do |csv|
csv << [:foo, 0]
csv << [:bar, 1]
csv << [:baz, 2]
end
str # => "foo,0bar,1baz,2"
ary = CSV.parse(str, row_sep: row_sep)
ary # => [["foo", "0bar", "1baz", "2"]]
當row_sep
是符號:auto
(默認)時,生成使用"\n"
作為行分隔符:
str = CSV.generate do |csv|
csv << [:foo, 0]
csv << [:bar, 1]
csv << [:baz, 2]
end
str # => "foo,0\nbar,1\nbaz,2\n"
另一方麵,解析會調用行分隔符的自動發現。
自動發現會提前讀取數據,查找下一個 \r\n
、 \n
或 \r
序列。即使序列出現在帶引號的字段中,也會選擇該序列,假設在那裏有相同的行結尾。
例子:
str = CSV.generate do |csv|
csv << [:foo, 0]
csv << [:bar, 1]
csv << [:baz, 2]
end
str # => "foo,0\nbar,1\nbaz,2\n"
ary = CSV.parse(str)
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
如果滿足以下任一條件,則使用默認 $INPUT_RECORD_SEPARATOR
( $/
):
-
沒有找到這些序列。
-
數據為
ARGF
、STDIN
、STDOUT
或STDERR
。 -
該流僅可用於輸出。
顯然,發現需要一點時間。如果速度很重要,請手動 Set
。另請注意, IO
對象應在 Windows 上以二進製模式打開,如果此函數將用於 line-ending 翻譯可能會導致將文檔位置重置為預讀之前的位置時出現問題。
如果給定值不是String-convertible,則引發異常:
row_sep = BasicObject.new
# Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
CSV.generate(ary, row_sep: row_sep)
# Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
CSV.parse(str, row_sep: row_sep)
選項col_sep
指定用於解析和生成的字符串字段分隔符。 String 在使用前會被轉碼為數據的 Encoding。
默認值:
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)
如果給定值不是String-convertible,則引發異常:
col_sep = BasicObject.new
# Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
CSV.generate(line, col_sep: col_sep)
# Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
CSV.parse(str, col_sep: col_sep)
選項quote_char
指定用於在解析和生成中引用字段的字符(長度為 1 的字符串)。這個 String
會在使用前轉碼成數據的Encoding。
默認值:
CSV::DEFAULT_OPTIONS.fetch(:quote_char) # => "\"" (double quote)
這對於錯誤地使用 '
(single-quote) 而不是正確的 "
(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"]]
使用'
(single-quote):
quote_char = "'"
str = CSV.generate(quote_char: quote_char) do |csv|
csv << ['foo', 0]
csv << ["'bar'", 1]
csv << ['"baz"', 2]
end
str # => "foo,0\n'''bar''',1\n\"baz\",2\n"
ary = CSV.parse(str, quote_char: quote_char)
ary # => [["foo", "0"], ["'bar'", "1"], ["\"baz\"", "2"]]
如果字符串長度大於 1,則引發異常:
# Raises ArgumentError (:quote_char has to be nil or a single character String)
CSV.new('', quote_char: 'xx')
如果值不是字符串,則引發異常:
# Raises ArgumentError (:quote_char has to be nil or a single character String)
CSV.new('', quote_char: :foo)
選項write_headers
指定確定標題行是否包含在輸出中的布爾值;如果沒有標題,則忽略。
默認值:
CSV::DEFAULT_OPTIONS.fetch(:write_headers) # => nil
沒有 write_headers
:
file_path = 't.csv'
CSV.open(file_path,'w',
:headers => ['Name','Value']
) do |csv|
csv << ['foo', '0']
end
CSV.open(file_path) do |csv|
csv.shift
end # => ["foo", "0"]
使用write_headers
“:
CSV.open(file_path,'w',
:write_headers=> true,
:headers => ['Name','Value']
) do |csv|
csv << ['foo', '0']
end
CSV.open(file_path) do |csv|
csv.shift
end # => ["Name", "Value"]
選項force_quotes
指定確定每個輸出字段是否要雙引號的布爾值。
默認值:
CSV::DEFAULT_OPTIONS.fetch(:force_quotes) # => false
對於本節中的示例:
ary = ['foo', 0, nil]
使用默認值 false
:
str = CSV.generate_line(ary)
str # => "foo,0,\n"
使用 true
:
str = CSV.generate_line(ary, force_quotes: true)
str # => "\"foo\",\"0\",\"\"\n"
選項quote_empty
指定確定是否將空值用雙引號引起來的布爾值。
默認值:
CSV::DEFAULT_OPTIONS.fetch(:quote_empty) # => true
使用默認 true
:
CSV.generate_line(['"', ""]) # => "\"\"\"\",\"\"\n"
使用 false
:
CSV.generate_line(['"', ""], quote_empty: false) # => "\"\"\"\",\n"
選項write_converters
指定生成字段時使用的轉換器。請參閱寫入轉換器
默認值:
CSV::DEFAULT_OPTIONS.fetch(:write_converters) # => nil
沒有寫轉換器:
str = CSV.generate_line(["\na\n", "\tb\t", " c "])
str # => "\"\na\n\",\tb\t, c \n"
使用寫轉換器:
strip_converter = proc {|field| field.strip }
str = CSV.generate_line(["\na\n", "\tb\t", " c "], write_converters: strip_converter)
str # => "a,b,c\n"
使用兩個寫轉換器(按順序調用):
upcase_converter = proc {|field| field.upcase }
downcase_converter = proc {|field| field.downcase }
write_converters = [upcase_converter, downcase_converter]
str = CSV.generate_line(['a', 'b', 'c'], write_converters: write_converters)
str # => "a,b,c\n"
另請參閱寫入轉換器
如果轉換器返回的值既不是nil
也不是String-convertible,則引發異常:
bad_converter = proc {|field| BasicObject.new }
# Raises NoMethodError (undefined method `is_a?' for #<BasicObject:>)
CSV.generate_line(['a', 'b', 'c'], write_converters: bad_converter)#
選項write_nil_value
指定要替換每個 nil
值字段的對象。
默認值:
CSV::DEFAULT_OPTIONS.fetch(:write_nil_value) # => nil
沒有選項:
str = CSV.generate_line(['a', nil, 'c', nil])
str # => "a,,c,\n"
使用以下選項:
str = CSV.generate_line(['a', nil, 'c', nil], write_nil_value: "x")
str # => "a,x,c,x\n"
選項write_empty_value
指定要替換具有空字符串的每個字段的對象。
默認值:
CSV::DEFAULT_OPTIONS.fetch(:write_empty_value) # => ""
沒有選項:
str = CSV.generate_line(['a', '', 'c', ''])
str # => "a,\"\",c,\"\"\n"
使用以下選項:
str = CSV.generate_line(['a', '', 'c', ''], write_empty_value: "x")
str # => "a,x,c,x\n"
帶標題的 CSV
CSV
允許指定 CSV
文件的列名,無論它們是在數據中,還是單獨提供。如果指定了標頭,則讀取方法會返回 CSV::Table
的實例,其中包含 CSV::Row
。
# Headers are part of data
data = CSV.parse(<<~ROWS, headers: true)
Name,Department,Salary
Bob,Engineering,1000
Jane,Sales,2000
John,Management,5000
ROWS
data.class #=> CSV::Table
data.first #=> #<CSV::Row "Name":"Bob" "Department":"Engineering" "Salary":"1000">
data.first.to_h #=> {"Name"=>"Bob", "Department"=>"Engineering", "Salary"=>"1000"}
# Headers provided by developer
data = CSV.parse('Bob,Engineering,1000', headers: %i[name department salary])
data.first #=> #<CSV::Row name:"Bob" department:"Engineering" salary:"1000">
轉換器
默認情況下,CSV 解析的每個值(字段或標題)都形成一個字符串。您可以使用 field
converter
或 header
converter
來攔截和修改解析的值:
-
請參閱現場轉換器。
-
請參閱標頭轉換器。
同樣默認情況下,生成期間要寫入的每個值都是“按原樣”寫入的。您可以使用 write
converter
在寫入之前修改值。
-
請參閱寫入轉換器。
指定轉換器
您可以在各種 CSV 方法的 options
參數中指定用於解析或生成的轉換器:
-
用於轉換解析的字段值的選項
converters
。 -
選項
header_converters
用於轉換已解析的標頭值。 -
選項
write_converters
用於轉換要寫入(生成)的值。
指定轉換器的三種形式:
-
轉換器過程:用於轉換的可執行代碼。
-
轉換器名稱:存儲的轉換器的名稱。
-
轉換器列表:轉換器過程、轉換器名稱和轉換器列表的數組。
轉換器過程
此轉換器過程 strip_converter
接受一個值 field
並返回 field.strip
:
strip_converter = proc {|field| field.strip }
在對 CSV.parse
的調用中,關鍵字參數 converters: string_converter
指定:
-
將為每個解析的字段調用 Proc
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"]]
轉換器 proc 可以接收第二個參數 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
:將每個 String-embedded 整數轉換為真正的整數。 -
:float
:將每個 String-embedded 浮點數轉換為真正的浮點數。 -
:date
:將每個 String-embedded 日期轉換為真實日期。 -
:date_time
:將每個 String-embedded 日期時間轉換為真正的 DateTime
.此示例創建一個轉換器 proc,然後將其存儲:
strip_converter = proc {|field| field.strip }
CSV::Converters[:strip] = strip_converter
然後解析方法調用可以通過其名稱引用轉換器,:strip
:
string = " foo , 0 \n bar , 1 \n baz , 2 \n"
array = CSV.parse(string, converters: :strip)
array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
標頭轉換器的存儲結構是 Hash CSV::HeaderConverters
,其工作方式相同。它還具有內置的轉換器過程:
-
:downcase
:縮小每個標題。 -
:symbol
:將每個標頭轉換為符號。
寫頭沒有這樣的存儲結構。
為了使解析方法能夠訪問存儲在非主 Ractor 中的轉換器,必須首先使存儲結構可共享。因此,必須在創建使用存儲在這些結構中的轉換器的 Ractor 之前調用 Ractor.make_shareable(CSV::Converters)
和 Ractor.make_shareable(CSV::HeaderConverters)
。 (由於使存儲結構可共享涉及凍結它們,因此必須首先添加要使用的任何自定義轉換器。)
轉換器列表
converter
list
是一個數組,可以包括以下任何種類:
-
轉換器過程。
-
存儲的轉換器的名稱。
-
嵌套轉換器列表。
例子:
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
所做的。)
有三種方法可以使用場轉換器。
-
使用帶有解析方法的選項轉換器:
ary = CSV.parse(string, converters: :integer) ary # => [0, 1, 2] # => [["foo", 0], ["bar", 1], ["baz", 2]]
-
將選項轉換器與新的 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]]
安裝字段轉換器不會影響 already-read 行:
csv = CSV.new(string)
csv.shift # => ["foo", "0"]
# Add a converter.
csv.convert(:integer)
csv.converters # => [:integer]
csv.read # => [["bar", 1], ["baz", 2]]
有額外的內置轉換器,也支持自定義轉換器。
內置場轉換器
內置字段轉換器在 Hash 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 Hash 中注冊轉換器,它允許您按名稱引用它:
CSV::Converters[:strip] = strip_converter
string = " foo , 0 \n bar , 1 \n baz , 2 \n"
array = CSV.parse(string, converters: :strip)
array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
標頭轉換器
標頭轉換器僅在標頭上運行(而不在其他行上)。
使用標頭轉換器有三種方法;這些示例使用內置的標頭轉換器 :dowhcase
,它將每個已解析的標頭小寫。
-
帶有單例解析方法的選項
header_converters
: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"]
-
帶有新 CSV 實例的選項
header_converters
: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"]
內置標題轉換器
內置的標頭轉換器位於 Hash 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"]
Converter :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 Hash 中注冊轉換器,這樣您就可以通過名稱來引用它:
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
對象的 Encoding
中工作。您的數據永遠不會被轉碼(除非您要求 Ruby 為您轉碼),並且會在它所在的 Encoding
中進行解析。因此, CSV
將在您的數據的 Encoding
中返回數組或字符串行。這是通過將解析器本身轉碼到您的 Encoding
中來完成的。
當然,為了實現這種多編碼支持,必須進行一些轉碼。例如,:col_sep
、:row_sep
和 :quote_char
必須進行轉碼以匹配您的數據。希望這能讓整個過程變得透明,因為 CSV 的默認值應該隻是神奇地適用於您的數據。但是,您可以在目標 Encoding
中手動設置這些值以避免轉換。
同樣重要的是要注意,雖然 CSV 的所有核心解析器現在都與 Encoding
無關,但有些函數不是。例如,內置轉換器會在進行轉換之前嘗試將數據轉碼為 UTF-8。同樣,您可以提供知道您的編碼的自定義轉換器以避免這種轉換。在所有 Ruby 編碼中支持原生轉換對我來說太難了。
無論如何,實際操作很簡單:確保傳遞給 CSV
的 IO
和 String
對象具有正確的 Encoding
設置,並且一切都應該正常工作。 CSV
方法允許您打開 IO
對象( CSV::foreach()
、 CSV::open()
、 CSV::read()
和 CSV::readlines()
)允許您指定 Encoding
。
將 CSV
生成為 String
時出現一個小例外,其中 Encoding
與ASCII 不兼容。 CSV
沒有可用於自行準備的現有數據,因此在大多數情況下,您可能需要手動指定所需的 Encoding
。但是,當使用 CSV::generate_line()
或 Array#to_csv() 時,它會嘗試使用輸出行中的字段進行猜測。
我嘗試在方法文檔中指出任何其他 Encoding
問題。
已經盡我所能對 Ruby 附帶的所有非“dummy” 編碼進行了測試。然而,它是勇敢的新代碼,可能有一些錯誤。如果您發現任何問題,請隨時report。
相關用法
- Ruby CSV.header_convert用法及代碼示例
- Ruby CSV.skip_lines用法及代碼示例
- Ruby CSV.table用法及代碼示例
- Ruby CSV.force_quotes?用法及代碼示例
- Ruby CSV.unconverted_fields?用法及代碼示例
- Ruby CSV.generate_line用法及代碼示例
- Ruby CSV.col_sep用法及代碼示例
- Ruby CSV.shift用法及代碼示例
- Ruby CSV.skip_blanks?用法及代碼示例
- Ruby CSV.read用法及代碼示例
- Ruby CSV.row_sep用法及代碼示例
- Ruby CSV.header_row?用法及代碼示例
- Ruby CSV.headers用法及代碼示例
- Ruby CSV.csv << row用法及代碼示例
- Ruby CSV.encoding用法及代碼示例
- Ruby CSV.each用法及代碼示例
- Ruby CSV.return_headers?用法及代碼示例
- Ruby CSV.converters用法及代碼示例
- Ruby CSV.line用法及代碼示例
- Ruby CSV.parse_line用法及代碼示例
- Ruby CSV.convert用法及代碼示例
- Ruby CSV.parse用法及代碼示例
- Ruby CSV.line_no用法及代碼示例
- Ruby CSV.instance用法及代碼示例
- Ruby CSV.liberal_parsing?用法及代碼示例
注:本文由純淨天空篩選整理自ruby-lang.org大神的英文原創作品 CSV類。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。