【问题标题】:How can I further process the line of data that causes the Ruby FasterCSV library to throw a MalformedCSVError?如何进一步处理导致 Ruby FasterCSV 库抛出 MalformedCSVError 的数据行?
【发布时间】:2011-12-02 00:52:36
【问题描述】:

传入的数据文件包含格式错误的 CSV 数据,例如非转义引号,以及(有效)CSV 数据,例如包含新行的字段。如果检测到 CSV 格式错误,我想对该数据使用替代例程。

使用以下示例代码(为简单起见)

FasterCSV.open( file ){|csv|
  row = true
  while row
    begin
      row = csv.shift
      break unless row
      # Do things with the good rows here...

    rescue FasterCSV::MalformedCSVError => e
      # Do things with the bad rows here...
      next
    end
  end
}

MalformedCSVError 是在 csv.shift 方法中引起的。如何从救援子句访问导致错误的数据?

【问题讨论】:

    标签: ruby fastercsv


    【解决方案1】:
    require 'csv' #CSV in ruby 1.9.2 is identical to FasterCSV
    
    # File.open('test.txt','r').each do |line|
    DATA.each do |line|
      begin
        CSV.parse(line) do |row|
          p row #handle row
        end
      rescue  CSV::MalformedCSVError => er
        puts er.message
        puts "This one: #{line}"
        # and continue
      end
    end
    
    # Output:
    
    # Unclosed quoted field on line 1.
    # This one: 1,"aaa
    # Illegal quoting on line 1.
    # This one: aaa",valid
    # Unclosed quoted field on line 1.
    # This one: 2,"bbb
    # ["bbb", "invalid"]
    # ["3", "ccc", "valid"]   
    
    __END__
    1,"aaa
    aaa",valid
    2,"bbb
    bbb,invalid
    3,ccc,valid
    

    只需将文件逐行输入 FasterCSV 并挽救错误。

    【讨论】:

    • 这也是我的第一直觉,但正如我在回答中指出的那样,我担心这将等同于对性能的巨大影响,因为FasterCSV.parse 每次都会实例化一个新的 FasterCSV 对象。 FasterCSV 的构造函数并不是特别庞大,但如果你必须对一个 1000 万行文件中的每一行都执行此操作,它会很快加起来。
    • 这将如何处理包含新行的有效 CSV 行?
    • 这是两行,@steenslag,将被File#each分开。
    • @Jordan 我们说的是同一件事吗? (添加示例数据并输出到代码)。
    • @steenslag 您的 DATA 部分有文字 \ 和 n 个字符,而不是换行符控制字符(您不再使用 Ruby,请记住 - 在 __END__ 之后,反斜杠只是一个反斜杠)。我已经更新了您的代码(希望您不介意,请随时恢复它)以显示实际用例和输出。紧随 __END__ 之后的两行构成 CSV 中的一个(有效)“行”。
    【解决方案2】:

    这将是非常困难的。一些使 FasterCSV,嗯,更快的东西,让这变得特别困难。这是我最好的建议:FasterCSV 可以包装 IO 对象。那么,您可以做的是创建自己的File 子类(它本身是IO 的子类),它“保留”最后一个gets 的结果。然后,当 FasterCSV 引发异常时,您可以向您的特殊 File 对象询问最后一行。像这样的:

    class MyFile < File
      attr_accessor :last_gets
      @last_gets = ''
    
      def gets(*args)
        line = super
        @last_gets << $/ << line
        line
      end
    end
    
    # then...
    
    file  = MyFile.open(filename, 'r')
    csv   = FasterCSV.new file
    
    row = true
    while row
      begin
        break unless row = csv.shift
    
        # do things with the good row here...
    
      rescue FasterCSV::MalformedCSVError => e
        bad_row = file.last_gets
    
        # do something with bad_row here...
    
        next
      ensure
        file.last_gets = '' # nuke the @last_gets "buffer"
      end
    end
    

    有点整洁,对吧? 但是!当然有一些警告:

    1. 我不确定当您在每个 gets 调用中添加一个额外的步骤时会对性能造成多大影响。如果您需要及时解析数百万行的文件,这可能是个问题。

    2. 如果您的 CSV 文件在带引号的字段中包含换行符,则此 完全失败 可能会失败,也可能不会失败。原因是described in the source——基本上,如果引用的值包含换行符,那么shift 必须执行额外的gets 调用才能获得整行。解决这个限制可能有一个聪明的方法,但它现在还没有出现。如果您确定您的文件在引用字段中没有任何换行符,那么您不必担心。

    您的 other 选项是使用 File.gets 读取文件并将每一行依次传递给 FasterCSV#parse_line 但我很确定这样做会浪费任何获得的性能优势使用 FasterCSV。

    【讨论】:

    • 确实,如前所述,这些文件可能包含带引号的换行符。我可以通过使用 FasterCSV 参数来避免未转义的引号错误:quote_char => '|',但这会阻塞换行符...
    • 没错。我确实提出了一个部分解决方案,我已经更改了我的代码以反映。不是在每个File#gets 上都有一个新的@last_gets,而是每次都将最后一个块附加到它,然后仅在成功检索到一行后重置它引发异常。不,它仍然不是一个完整的解决方案,但我希望它能给你一两个想法。
    【解决方案3】:

    在 CSV 尝试解析输入数据之前,我使用 Jordan 的文件子类化方法解决了输入数据的问题。就我而言,我有一个文件使用 \" 来转义引号,而不是 CSV 期望的 ""。因此,

    class MyFile < File
      def gets(*args)
        line = super
        if line != nil
          line.gsub!('\\"','""')  # fix the \" that would otherwise cause a parse error
        end
        line
      end
    end
    
    infile = MyFile.open(filename)
    incsv = CSV.new(infile)
    
    while row = infile.shift
      # process each row here
    end
    

    这让我可以解析非标准的 CSV 文件。 Ruby 的 CSV 实现非常严格,并且经常遇到 CSV 格式的许多变体的问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-10-19
      • 2011-01-25
      • 1970-01-01
      • 1970-01-01
      • 2011-09-08
      • 2020-08-26
      • 1970-01-01
      • 2020-07-09
      相关资源
      最近更新 更多