【问题标题】:CSV parsing returns "Unquoted fields do not allow \r or \n" but can't find error in source file?CSV 解析返回“未加引号的字段不允许 \r 或 \n”但在源文件中找不到错误?
【发布时间】:2019-01-29 00:12:00
【问题描述】:

我正在为我的 Rails 应用程序使用 Ruby 中的内置 CSV 函数。我正在调用一个 URL(通过 HTTParty)来解析它,并尝试将结果保存到我的数据库中。

问题是,我收到错误Unquoted fields do not allow \r or \n,这表明通常输入数据有问题,但在检查数据时,我找不到任何问题。

我是这样检索数据的:

response = HTTParty.get("http://" + "weather.com/ads.txt", limit: 100, follow_redirects: true, timeout: 10)

(此数据可在网址 weather.com/ads.txt 上公开获得)

然后我尝试解析数据,应用一些正则表达式来忽略 # 之后的所有内容,忽略空行等。

if response.code == 200 && !response.body.match(/<.*html>/) active_policies = []

CSV.parse(response.body, skip_blanks: true, skip_lines: /(^\s*#|^\s*$|^contact=|^CONTACT=|^subdomain=)/) do |row|
    begin
     #print out the individual ads.txt records 
     puts ""
     print row[0].downcase.strip + " " + row[1].strip + " " + 
     row[2].split("#").first.strip
            active_policies.push(
                publisher.policies.find_or_create_by(ad_partner: row[0].downcase.strip, external_seller_id: row[1].strip, seller_relationship: row[2].split("#").first.strip) do |policy|
                    policy.deactivated_at = nil
                end 
                )

                rescue => save
                #Add error event to the new sync status model
                puts "we are in the loop"
                puts save.message, row.inspect, save.backtrace
                    next
                end
                end
            #else
                #puts "Too many policies.  Skipping " + publisher.name
            #end
            #now we are going to run a check to see if we have any policies that are outdated, and if so, flag them as such.
            deactivated_policies = publisher.policies.where.not(id: active_policies.map(&:id)).where(deactivated_at: nil)
            deactivated_policies.update_all(deactivated_at: Time.now)
            deactivated_policies.each do |deactivated_policy|
                puts "Deactivating Policy for " + deactivated_policy.publisher.name
            end

         elsif response.code == 404 
            print 
            print response.code.to_s + " GET, "  + response.body.size.to_s + " body, "
            puts response.headers.size.to_s + " headers for " + publisher.name

         elsif response.code == 302
            print response.code.to_s + " GET, "  + publisher.name
         else 
            puts response.code.to_s +  " GET ads txt not found on " + publisher.name
         end

    publisher.update(last_scan: Time.now)

    rescue => ex
        puts ex.message, ex.backtrace, "error pulling #{publisher.name} ..." 
        #publisher.update_columns(active: "false")
    end
end`

我的一些想法/调查结果:

  1. 我已尝试逐行浏览这一行,我发现第 134 行是中断扫描的原因。我通过像这样进行手动检查来做到这一点: CSV.parse(response.body.lines[140..400].join("\n"), skip_blanks: true, skip_lines: /(^\s*#|^\s*$|^contact=|^CONTACT=|^subdomain=)/) 但这对我没有帮助,因为即使我将第 134 行标识为违规行,我也不知道如何检测或处理它。

    1. 我注意到源文件(位于 weather.com/ads.txt)有不寻常的字符,但即使通过 response.body.force_encoding("UTF-8") 将其强制为 utf-8 仍然会引发错误。

    2. 我尝试将 next 添加到救援块,因此即使它发现错误,它也会移动到 csv 中的下一行,但这不会发生 - 它只是出错并停止解析 - 所以我得到了前 130~ 个条目,但没有得到剩余的条目。

    3. 类似于页面类型,我不确定页面类型是 HTML 而不是文本文件是否会在此处产生问题。

我很想知道如何检测和处理此错误,因此欢迎提出任何想法!

作为参考,#PBS 显然是在源文件中给我带来麻烦的第 134 行,但我不知道我是否完全相信这是问题所在。

#canada

google.com, pub-0942427266003794, DIRECT, f08c47fec0942fa0
indexexchange.com, 184315, DIRECT
indexexchange.com, 184601, DIRECT
indexexchange.com, 182960, DIRECT
openx.com, 539462051, DIRECT, 6a698e2ec38604c6

#spain

#PBS
google.com, pub-8750086020675820, DIRECT, f08c47fec0942fa0
google.com, pub-1072712229542583, DIRECT, f08c47fec0942fa0
appnexus.com, 3872, DIRECT
rubiconproject.com, 9778, DIRECT, 0bfd66d529a55807
openx.com, 539967419, DIRECT, 6a698e2ec38604c6
openx.com, 539726051, DIRECT, 6a698e2ec38604c6
google.com, pub-7442858011436823, DIRECT, f08c47fec0942fa0

【问题讨论】:

    标签: ruby-on-rails ruby csv parsing error-handling


    【解决方案1】:

    该文本中存在不一致的行尾,CSV 解析器会遇到这些问题。一个非常快速的解决方法是删除所有 \r 字符:

    response.body.gsub!("\r", '')
    

    如果您好奇,查看错误字符的一种方法是使用以下代码将每个字符的 Ruby 数组表示法写入文本文件:

    response = HTTParty.get("http://" + "weather.com/ads.txt", limit: 100, follow_redirects: true, timeout: 10)
    characters = response.chars.inspect
    output = File.open( "outputfile.txt","w" )
    output << characters
    output.close
    

    打开outputfile.txt 并搜索\r 字符。我在行尾发现了其中的几个,尽管所有其他行都以 \n 单独结束。

    【讨论】:

    • response.body.gsub!("\r", '') 解决了!我很好奇,outputfile.txt 的位置在哪里?抱歉,如果这是一个愚蠢的问题,但我有另一个问题,我怀疑是同样的问题 - 我收到了 techradar.com/ads.txt 的错误Illegal quoting in line 540.,我认为这里也存在隐藏/错误字符, 只是不换行
    • @bkimble 的另一个答案使用tr() 而不是gsub(),这对于像这样的单个字符删除可能是更有效的选择。 outputfile.txt 将由 Rails 项目根目录中的代码创建。您看到的行号 540 可能有点误导,因为某些行在 CSV 分配行号之前被跳过。非法引用居然在580行:tremorhub.com, q017o-78mlk, RESELLER, 1a4e959a1b50034a # Premium video demand aka "Telaria" #
    • 好的,我将进行更改以使用 tr() - 为了避免“Telaria”问题,我是否可以通过正则表达式控制引号?
    • 你可以,我猜。您还可以使用tr()gsub() 删除所有引号包。尽管其中任何一个都可能很混乱,因为引号也是 .csv 文件中的合法分隔符,只是在这个文件中没有使用。我注意到给您带来麻烦的引号在您要删除的 # 之后的文本中。但是,您在 CSV 解析行后将其删除。考虑事先将其删除。
    【解决方案2】:

    看起来发生的事情是输入文件的行以 \n 终止,但第 134 和 135 行除外,它们以 \r\n 终止。默认情况下,CSV 将其 :row_sep 设置为 :auto,它会查看文件以确定哪个分隔符最合适,并选择“\n”。那些额外的回车会让它认为你有一个没有被引号封装的多行字段。

    您可以通过在 CSV 获取文件之前预先解析文件并删除 \r:

    来解决此问题

    变化:

    CSV.parse(response.body, skip_blanks: true, skip_lines: /(^\s*#|^\s*$|^contact=|^CONTACT=|^subdomain=)/) do |row|
    

    到:

    CSV.parse(response.body.tr("\r", ''), skip_blanks: true, skip_lines: /(^\s*#|^\s*$|^contact=|^CONTACT=|^subdomain=)/) do |row|
    

    【讨论】:

      猜你喜欢
      • 2021-11-11
      • 1970-01-01
      • 1970-01-01
      • 2012-03-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-29
      相关资源
      最近更新 更多