解析 CSV 文件中由分隔符分隔的每个文本的值

Parsing values of each and every text separated by delimiter in CSV file

正在尝试创建读取和显示 CSV 文件中每个值的方法。已将 CSV 文件的第一行指定为函数名称,可以调用这些函数来访问每个文本。 我还构建了一个对象数组,并将每个对象与 CSV 文件的行相关联。 CSV 文件的输入被视为由分隔符分隔的普通文本。假设-

    name,age,city 
    Chris,43,Ohio
    Tony,54,NYC

我的输出是正确的,它是通过提要生成器提取到另一个 CSV 文件的 class。 但我无法在命令行上解析此输出。我可以在 class 之外的 FeedGenerator 上直接调用方法,例如 -

        FeedGenerator.name
        FeedGenerator.age
        FeedGenerator.city

目前我的代码根据此 class -

中提供的属性提供数据
    class StarkFeedGenerator < FeedGenerator
      def columns; %w(name); end
    end
    require 'csv'

    class FeedGenerator
      attr_accessor :source, :feed, :current_row

      def initialize(source_name, feed_name)
        @source = CSV.read(source_name, headers: true)
        @current_row = Row.new
        @feed = []

        # define method by header of source file
        @source.headers.each do |column|
          @current_row.instance_eval do
            define_singleton_method(column) do
              self.row[column]
            end
          end
        end

        @feed = CSV.open(feed_name, 'wb+')
        @feed << columns
      end

      def columns
         %w(name age city)
      end

      def generate_feed
        @source.each do |row|
          @current_row.row = row
          @feed << columns.map do |c|
            @current_row.send(c)
          end
        end
      end

      def columns; raise 'unimplimented'; end

      class Row
        attr_accessor :row

        # you can define unrecognized column mapping below
        def name; name; end
        def age; age; end
        def city; city; end
      end
    end
    class StarkFeedGenerator < FeedGenerator
      def columns; %w(name); end
    end

    StarkFeedGenerator.new('Input.csv','new_feed.csv').generate_feed

预期结果:

    FeedGenerator.name : Chris, tony
    FeedGenerator.age : 43,54
    FeedGenerator.city : Ohio, NYC

这是你想要的吗?

require 'csv'

class Feed
  def initialize(source_name, column_names = [])
    if column_names.empty?
      column_names = CSV.open(source_name, 'r', &:first)
    end
    columns = column_names.reduce({}) { |columns, col_name| columns[col_name] = []; columns }

    define_singleton_method(:columns) { column_names }

    column_names.each do |col_name|
      define_singleton_method(col_name.to_sym) { columns[col_name] }
    end

    CSV.foreach(source_name, headers: true) do |row|
      column_names.each do |col_name|
        columns[col_name] << row[col_name]
      end
    end
  end
end

feed = Feed.new('input.csv')
puts feed.columns # ["name", "age", "city"]
puts feed.name # ["Chris", "Tony"]
puts feed.age # ["43", "54"]
puts feed.city # ["Ohio", "NYC"]

feed2 = Feed.new('input.csv', ['name'])
puts feed2.columns # ["name"]
puts feed2.name # ["Chris", "Tony"]

请注意,我刚刚创建了 Feed class 而不是 FeedGenerator,因为我认为创建一个生成器没有多大意义,而您只需 initialize方法。

另请注意,如果您只想在调用 feed.name 时从 CSV 文件中读取数据,那么所有 CSV 行都将存储在内存中(如果您的 CSV 非常大则效果不佳),例如,这是另一种方法:

require 'csv'

class Feed
  def initialize(source_name, column_names = [])
    if column_names.empty?
      column_names = CSV.open(source_name, 'r', &:first)
    end

    define_singleton_method(:columns) { column_names }

    column_names.each do |col_name|
      define_singleton_method(col_name.to_sym) do
        columns = []
        CSV.foreach(source_name, headers: true) do |row|
          columns << row[col_name]
        end
        columns
      end
    end
  end
end

feed = Feed.new('input.csv')