class CSV::Row

CSV::Row

CSV::Row 实例表示 CSV 表格中的一行。(请参阅 class CSV)。

该实例可能具有:

  • 字段:每个字段都是一个对象,不一定是字符串。

  • 标题:每个标题用作键,也不一定是字符串。

实例方法

CSV::Row 有三组实例方法:

  • 自身内部定义的实例方法。

  • 模块 Enumerable 包含的方法。

  • 委托给 Array 类的方法。

    • Array#empty?

    • Array#length

    • Array#size

创建 CSV::Row 实例

通常,新的 CSV::Row 实例是通过解析带有标题的 CSV 源创建的。

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
table.each {|row| p row }

输出

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

您也可以直接创建行。请参阅 ::new

标题

像 CSV::Table 一样,CSV::Row 也有标题。

通过解析 CSV 源创建的 CSV::Row 会从表格中继承其标题。

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
row = table.first
row.headers # => ["Name", "Value"]

您也可以使用标题创建新行;像哈希中的键一样,标题不必是字符串。

row = CSV::Row.new([:name, :value], ['foo', 0])
row.headers # => [:name, :value]

即使添加到具有标题的表格中,新行也会保留其标题。

table << row # => #<CSV::Table mode:col_or_row row_count:5>
row.headers # => [:name, :value]
row[:name] # => "foo"
row['Name'] # => nil

访问字段

您可以使用整数索引(数组样式)或标题(哈希样式)访问 CSV::Row 中的字段。

使用方法 [] 获取字段

row = CSV::Row.new(['Name', 'Value'], ['foo', 0])
row[1] # => 0
row['Value'] # => 0

使用方法 []= 设置字段

row = CSV::Row.new(['Name', 'Value'], ['foo', 0])
row # => #<CSV::Row "Name":"foo" "Value":0>
row[0] = 'bar'
row['Value'] = 1
row # => #<CSV::Row "Name":"bar" "Value":1>

属性

row[R]

用于比较相等性的内部数据格式。

公共类方法

CSV::Row.new(headers, fields, header_row = false) → csv_row 点击切换源

返回从参数 headersfields 构造的新 CSV::Row 实例;两者都应为数组;请注意,字段不必是字符串。

row = CSV::Row.new(['Name', 'Value'], ['foo', 0])
row # => #<CSV::Row "Name":"foo" "Value":0>

如果数组长度不同,则较短的数组将用 nil 填充。

row = CSV::Row.new(['Name', 'Value', 'Date', 'Size'], ['foo', 0])
row # => #<CSV::Row "Name":"foo" "Value":0 "Date":nil "Size":nil>

每个 CSV::Row 对象要么是字段行,要么是标题行;默认情况下,新行是字段行;对于上面创建的行。

row.field_row? # => true
row.header_row? # => false

如果可选参数 header_row 给定为 true,则创建的行是标题行。

row = CSV::Row.new(['Name', 'Value'], ['foo', 0], header_row = true)
row # => #<CSV::Row "Name":"foo" "Value":0>
row.field_row? # => false
row.header_row? # => true
# File csv-3.3.2/lib/csv/row.rb, line 105
def initialize(headers, fields, header_row = false)
  @header_row = header_row
  headers.each { |h| h.freeze if h.is_a? String }

  # handle extra headers or fields
  @row = if headers.size >= fields.size
    headers.zip(fields)
  else
    fields.zip(headers).each(&:reverse!)
  end
end

公共实例方法

row << [header, value] → self 点击切换源
row << hash → self
row << value → self

self 添加一个字段;返回 self

如果参数是 2 元素数组 [header, value],则会添加一个具有给定 headervalue 的字段。

source = "Name,Name,Name\nFoo,Bar,Baz\n"
table = CSV.parse(source, headers: true)
row = table[0]
row << ['NAME', 'Bat']
row # => #<CSV::Row "Name":"Foo" "Name":"Bar" "Name":"Baz" "NAME":"Bat">

如果参数是哈希,则每个 key-value 对将作为具有标题 key 和值 value 的字段添加。

source = "Name,Name,Name\nFoo,Bar,Baz\n"
table = CSV.parse(source, headers: true)
row = table[0]
row << {NAME: 'Bat', name: 'Bam'}
row # => #<CSV::Row "Name":"Foo" "Name":"Bar" "Name":"Baz" NAME:"Bat" name:"Bam">

否则,给定的 value 将作为没有标题的字段添加。

source = "Name,Name,Name\nFoo,Bar,Baz\n"
table = CSV.parse(source, headers: true)
row = table[0]
row << 'Bag'
row # => #<CSV::Row "Name":"Foo" "Name":"Bar" "Name":"Baz" nil:"Bag">
# File csv-3.3.2/lib/csv/row.rb, line 389
def <<(arg)
  if arg.is_a?(Array) and arg.size == 2  # appending a header and name
    @row << arg
  elsif arg.is_a?(Hash)                  # append header and name pairs
    arg.each { |pair| @row << pair }
  else                                   # append field value
    @row << [nil, arg]
  end

  self  # for chaining
end
row == other → true 或 false 点击切换源

如果 other 是 /CSV::Row,并且具有与 self 相同顺序的相同字段(标题和值),则返回 true;否则返回 false

source = "Name,Name,Name\nFoo,Bar,Baz\n"
table = CSV.parse(source, headers: true)
row = table[0]
other_row = table[0]
row == other_row # => true
other_row = table[1]
row == other_row # => false
# File csv-3.3.2/lib/csv/row.rb, line 633
def ==(other)
  return @row == other.row if other.is_a? CSV::Row
  @row == other
end
[](header_or_index, minimum_index = 0)
别名:field
row[index] = value → value 点击切换源
row[header, offset] = value → value
row[header] = value → value

为给定的 indexheader 分配字段值;返回 value


按整数索引分配字段值

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
row = table[0]
row[0] = 'Bat'
row[1] = 3
row # => #<CSV::Row "Name":"Bat" "Value":3>

如果 index 为负数,则从最后一列向后计数。

row[-1] = 4
row[-2] = 'Bam'
row # => #<CSV::Row "Name":"Bam" "Value":4>

如果正数 index 不在该行中,则使用 nil:nil 扩展该行。

row[4] = 5
row # => #<CSV::Row "Name":"bad" "Value":4 nil:nil nil:nil nil:5>

如果负数 index 太小(离零太远),则引发 IndexError。


按标题分配字段值(第一个找到的)

source = "Name,Name,Name\nFoo,Bar,Baz\n"
table = CSV.parse(source, headers: true)
row = table[0]
row['Name'] = 'Bat'
row # => #<CSV::Row "Name":"Bat" "Name":"Bar" "Name":"Baz">

按标题分配字段值,忽略 offset 个前导字段

source = "Name,Name,Name\nFoo,Bar,Baz\n"
table = CSV.parse(source, headers: true)
row = table[0]
row['Name', 2] = 4
row # => #<CSV::Row "Name":"Foo" "Name":"Bar" "Name":4>

通过(新)标题追加新字段

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
row = table[0]
row['New'] = 6
row# => #<CSV::Row "Name":"foo" "Value":"0" "New":6>
# File csv-3.3.2/lib/csv/row.rb, line 339
def []=(*args)
  value = args.pop

  if args.first.is_a? Integer
    if @row[args.first].nil?  # extending past the end with index
      @row[args.first] = [nil, value]
      @row.map! { |pair| pair.nil? ? [nil, nil] : pair }
    else                      # normal index assignment
      @row[args.first][1] = value
    end
  else
    index = index(*args)
    if index.nil?             # appending a field
      self << [args.first, value]
    else                      # normal header assignment
      @row[index][1] = value
    end
  end
end
deconstruct → array 点击切换源

返回适用于模式匹配的新数组,其中包含行的值。

# File csv-3.3.2/lib/csv/row.rb, line 682
def deconstruct
  fields
end
deconstruct_keys(keys) → hash 点击切换源

返回适用于模式匹配的新哈希,其中仅包含指定为参数的键。

# File csv-3.3.2/lib/csv/row.rb, line 667
def deconstruct_keys(keys)
  if keys.nil?
    to_h
  else
    keys.to_h { |key| [key, self[key]] }
  end
end
delete(index) → [header, value] 或 nil 点击切换源
delete(header) → [header, value] 或空数组
delete(header, offset) → [header, value] 或空数组

self 中删除指定的字段;如果字段存在,则返回 2 元素数组 [header, value]

如果给定了整数参数 index,则删除并返回偏移量为 index 的字段,如果该字段不存在,则返回 nil

source = "Name,Name,Name\nFoo,Bar,Baz\n"
table = CSV.parse(source, headers: true)
row = table[0]
row.delete(1) # => ["Name", "Bar"]
row.delete(50) # => nil

否则,如果给定了单个参数 header,则删除并返回第一个找到的具有给定标题的字段,如果该字段不存在,则返回新的空数组。

source = "Name,Name,Name\nFoo,Bar,Baz\n"
table = CSV.parse(source, headers: true)
row = table[0]
row.delete('Name') # => ["Name", "Foo"]
row.delete('NAME') # => []

如果给定了参数 header 和整数参数 offset,则删除并返回第一个找到的具有给定标题的字段,其 index 至少与 offset 一样大。

source = "Name,Name,Name\nFoo,Bar,Baz\n"
table = CSV.parse(source, headers: true)
row = table[0]
row.delete('Name', 1) # => ["Name", "Bar"]
row.delete('NAME', 1) # => []
# File csv-3.3.2/lib/csv/row.rb, line 451
def delete(header_or_index, minimum_index = 0)
  if header_or_index.is_a? Integer                 # by index
    @row.delete_at(header_or_index)
  elsif i = index(header_or_index, minimum_index)  # by header
    @row.delete_at(i)
  else
    [ ]
  end
end
delete_if {|header, value| ... } → self 点击切换源

删除块所选的 self 中的字段;返回 self

删除块返回真值时的每个字段。

source = "Name,Name,Name\nFoo,Bar,Baz\n"
table = CSV.parse(source, headers: true)
row = table[0]
row.delete_if {|header, value| value.start_with?('B') } # => true
row # => #<CSV::Row "Name":"Foo">
row.delete_if {|header, value| header.start_with?('B') } # => false

如果没有给出块,则返回新的枚举器。

row.delete_if # => #<Enumerator: #<CSV::Row "Name":"Foo">:delete_if>
# File csv-3.3.2/lib/csv/row.rb, line 476
def delete_if(&block)
  return enum_for(__method__) { size } unless block_given?

  @row.delete_if(&block)

  self  # for chaining
end
dig(index_or_header, *identifiers) → object 点击切换源

查找并返回嵌套对象中由 index_or_headerspecifiers 指定的对象。

嵌套对象可能是各种类的实例。请参阅 Dig 方法。

示例

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
row = table[0]
row.dig(1) # => "0"
row.dig('Value') # => "0"
row.dig(5) # => nil
# File csv-3.3.2/lib/csv/row.rb, line 715
def dig(index_or_header, *indexes)
  value = field(index_or_header)
  if value.nil?
    nil
  elsif indexes.empty?
    value
  else
    unless value.respond_to?(:dig)
      raise TypeError, "#{value.class} does not have \#dig method"
    end
    value.dig(*indexes)
  end
end
each {|header, value| ... } → self 点击切换源

使用每个标题-值对调用块;返回 self

source = "Name,Name,Name\nFoo,Bar,Baz\n"
table = CSV.parse(source, headers: true)
row = table[0]
row.each {|header, value| p [header, value] }

输出

["Name", "Foo"]
["Name", "Bar"]
["Name", "Baz"]

如果没有给出块,则返回新的枚举器。

row.each # => #<Enumerator: #<CSV::Row "Name":"Foo" "Name":"Bar" "Name":"Baz">:each>
# File csv-3.3.2/lib/csv/row.rb, line 610
def each(&block)
  return enum_for(__method__) { size } unless block_given?

  @row.each(&block)

  self  # for chaining
end
也别名为:each_pair
each_pair(&block)
别名:each
fetch(header) → value 点击切换源
fetch(header, default) → value
fetch(header) {|row| ... } → value

返回由 header 指定的字段值。


使用单个参数 header,返回该标题的字段值(第一个找到的)。

source = "Name,Name,Name\nFoo,Bar,Baz\n"
table = CSV.parse(source, headers: true)
row = table[0]
row.fetch('Name') # => "Foo"

如果标题不存在,则引发异常 KeyError


如果给定了参数 headerdefault,则如果标题存在,则返回该标题的字段值(第一个找到的),否则返回 default

source = "Name,Name,Name\nFoo,Bar,Baz\n"
table = CSV.parse(source, headers: true)
row = table[0]
row.fetch('Name', '') # => "Foo"
row.fetch(:nosuch, '') # => ""

如果给定了参数 header 和一个块,则如果标题存在,则返回该标题的字段值(第一个找到的);否则调用该块并返回其返回值。

source = "Name,Name,Name\nFoo,Bar,Baz\n"
table = CSV.parse(source, headers: true)
row = table[0]
row.fetch('Name') {|header| fail 'Cannot happen' } # => "Foo"
row.fetch(:nosuch) {|header| "Header '#{header} not found'" } # => "Header 'nosuch not found'"
# File csv-3.3.2/lib/csv/row.rb, line 258
def fetch(header, *varargs)
  raise ArgumentError, "Too many arguments" if varargs.length > 1
  pair = @row.assoc(header)
  if pair
    pair.last
  else
    if block_given?
      yield header
    elsif varargs.empty?
      raise KeyError, "key not found: #{header}"
    else
      varargs.first
    end
  end
end
field(index) → value 点击切换源
field(header) → value
field(header, offset) → value

返回给定 indexheader 的字段值。


按整数索引获取字段值

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
row = table[0]
row.field(0) # => "foo"
row.field(1) # => "bar"

如果 index 为负数,则从最后一列向后计数。

row.field(-1) # => "0"
row.field(-2) # => "foo"

如果 index 超出范围,则返回 nil

row.field(2) # => nil
row.field(-3) # => nil

按标题获取字段值(第一个找到的)

source = "Name,Name,Name\nFoo,Bar,Baz\n"
table = CSV.parse(source, headers: true)
row = table[0]
row.field('Name') # => "Foo"

按标题获取字段值,忽略 offset 个前导字段

source = "Name,Name,Name\nFoo,Bar,Baz\n"
table = CSV.parse(source, headers: true)
row = table[0]
row.field('Name', 2) # => "Baz"

如果标题不存在,则返回 nil

# File csv-3.3.2/lib/csv/row.rb, line 203
def field(header_or_index, minimum_index = 0)
  # locate the pair
  finder = (header_or_index.is_a?(Integer) || header_or_index.is_a?(Range)) ? :[] : :assoc
  pair   = @row[minimum_index..-1].public_send(finder, header_or_index)

  # return the field if we have a pair
  if pair.nil?
    nil
  else
    header_or_index.is_a?(Range) ? pair.map(&:last) : pair.last
  end
end
也别名为:[]
field?(value) → true 或 false 点击切换源

如果 value 是此行中的一个字段,则返回 true,否则返回 false

source = "Name,Name,Name\nFoo,Bar,Baz\n"
table = CSV.parse(source, headers: true)
row = table[0]
row.field?('Bar') # => true
row.field?('BAR') # => false
# File csv-3.3.2/lib/csv/row.rb, line 589
def field?(data)
  fields.include? data
end
field_row? → true 或 false 点击切换源

如果这是一个字段行,则返回 true,否则返回 false

# File csv-3.3.2/lib/csv/row.rb, line 148
def field_row?
  not header_row?
end
fields(*specifiers) → array_of_fields 点击切换源

根据给定的 specifiers 返回字段值,它可以是以下任何混合形式:

  • 整数索引。

  • 整数索引的范围。

  • 包含标题和偏移量的 2 元素数组。

  • 标题。

  • 标题的范围。

对于上面前四种情况中的一种 specifier,返回 self.field(specifier) 的结果;请参阅 field

尽管可以有任意数量的 specifiers,但此处的示例将一次说明一个。

当 specifier 是一个整数 index 时,返回 self.field(index)

source = "Name,Name,Name\nFoo,Bar,Baz\n"
table = CSV.parse(source, headers: true)
row = table[0]
row.fields(1) # => ["Bar"]

当 specifier 是一个整数范围 range 时,返回 self.field(range)

row.fields(1..2) # => ["Bar", "Baz"]

当 specifier 是一个 2 元素数组 array 时,返回 self.field(array)

row.fields('Name', 1) # => ["Foo", "Bar"]

当 specifier 是一个标题 header 时,返回 self.field(header)

row.fields('Name') # => ["Foo"]

当 specifier 是一个标题范围 range 时,从 range.startrange.end 的索引中形成一个新的范围 new_range,并返回 self.field(new_range)

source = "Name,NAME,name\nFoo,Bar,Baz\n"
table = CSV.parse(source, headers: true)
row = table[0]
row.fields('Name'..'NAME') # => ["Foo", "Bar"]

如果没有给出参数,则返回所有字段。

row.fields # => ["Foo", "Bar", "Baz"]
# File csv-3.3.2/lib/csv/row.rb, line 530
def fields(*headers_and_or_indices)
  if headers_and_or_indices.empty?  # return all fields--no arguments
    @row.map(&:last)
  else                              # or work like values_at()
    all = []
    headers_and_or_indices.each do |h_or_i|
      if h_or_i.is_a? Range
        index_begin = h_or_i.begin.is_a?(Integer) ? h_or_i.begin :
                                                    index(h_or_i.begin)
        index_end   = h_or_i.end.is_a?(Integer)   ? h_or_i.end :
                                                    index(h_or_i.end)
        new_range   = h_or_i.exclude_end? ? (index_begin...index_end) :
                                            (index_begin..index_end)
        all.concat(fields.values_at(new_range))
      else
        all << field(*Array(h_or_i))
      end
    end
    return all
  end
end
也别名为:values_at
has_key?(header) → true 或 false 点击切换源

如果存在具有给定 header 的字段,则返回 true,否则返回 false

# File csv-3.3.2/lib/csv/row.rb, line 279
def has_key?(header)
  !!@row.assoc(header)
end
也别名为:include?key?member?header?
header?(header)
别名:has_key?
header_row? → true 或 false 点击切换源

如果这是一个标题行,则返回 true,否则返回 false

# File csv-3.3.2/lib/csv/row.rb, line 140
def header_row?
  @header_row
end
headers → array_of_headers 点击切换源

返回此行的标题

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
row = table.first
row.headers # => ["Name", "Value"]
# File csv-3.3.2/lib/csv/row.rb, line 160
def headers
  @row.map(&:first)
end
include?(header)
别名:has_key?
index(header) → index 点击切换源
index(header, offset) → index

返回给定标题的索引(如果存在);否则返回 nil

使用单个参数 header,返回第一个找到的具有给定 header 的字段的索引。

source = "Name,Name,Name\nFoo,Bar,Baz\n"
table = CSV.parse(source, headers: true)
row = table[0]
row.index('Name') # => 0
row.index('NAME') # => nil

使用参数 headeroffset,返回第一个找到的具有给定 header 的字段的索引,但忽略前 offset 个字段。

row.index('Name', 1) # => 1
row.index('Name', 3) # => nil
# File csv-3.3.2/lib/csv/row.rb, line 573
def index(header, minimum_index = 0)
  # find the pair
  index = headers[minimum_index..-1].index(header)
  # return the index at the right offset, if we found one
  index.nil? ? nil : index + minimum_index
end
initialize_copy(other_row) → self 点击切换源

调用超类方法。

调用超类方法
# File csv-3.3.2/lib/csv/row.rb, line 130
def initialize_copy(other)
  super_return_value = super
  @row = @row.collect(&:dup)
  super_return_value
end
inspect → string 点击切换源码

返回一个显示

  • CSV::Row 类的 ASCII 兼容字符串。

  • 头-值对。

示例

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
row = table[0]
row.inspect # => "#<CSV::Row \"Name\":\"foo\" \"Value\":\"0\">"
# File csv-3.3.2/lib/csv/row.rb, line 740
def inspect
  str = ["#<", self.class.to_s]
  each do |header, field|
    str << " " << (header.is_a?(Symbol) ? header.to_s : header.inspect) <<
           ":" << field.inspect
  end
  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
key?(header)
别名:has_key?
member?(header)
别名:has_key?
push(*values) → self 点击切换源码

将给定的每个 values 追加到 self 作为字段;返回 self

source = "Name,Name,Name\nFoo,Bar,Baz\n"
table = CSV.parse(source, headers: true)
row = table[0]
row.push('Bat', 'Bam')
row # => #<CSV::Row "Name":"Foo" "Name":"Bar" "Name":"Baz" nil:"Bat" nil:"Bam">
# File csv-3.3.2/lib/csv/row.rb, line 410
def push(*args)
  args.each { |arg| self << arg }

  self  # for chaining
end
to_csv → csv_string 点击切换源码

将行作为 CSV String 返回。不包含标题

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
row = table[0]
row.to_csv # => "foo,0\n"
# File csv-3.3.2/lib/csv/row.rb, line 694
def to_csv(**options)
  fields.to_csv(**options)
end
也别名为:to_s
to_h → hash 点击切换源码

返回一个新的哈希,该哈希通过将 self 中的每个头-值对作为哈希中的键-值对添加而形成。

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
row = table[0]
row.to_h # => {"Name"=>"foo", "Value"=>"0"}

保留标题顺序,但重复的标题将被忽略

source = "Name,Name,Name\nFoo,Bar,Baz\n"
table = CSV.parse(source, headers: true)
row = table[0]
row.to_h # => {"Name"=>"Foo"}
# File csv-3.3.2/lib/csv/row.rb, line 653
def to_h
  hash = {}
  each do |key, _value|
    hash[key] = self[key] unless hash.key?(key)
  end
  hash
end
也别名为:to_hash
to_hash()
别名为:to_h
to_s(**options)
别名为:to_csv
values_at(*headers_and_or_indices)
别名为:fields