【问题标题】:CSV::Row and Hash navigation not working Ruby 2.3.3 Rails 5.1CSV::Row 和 Hash 导航不起作用 Ruby 2.3.3 Rails 5.1
【发布时间】:2018-10-24 08:48:24
【问题描述】:

我已经使用 CSV.parse 解析了一个 csv,并且正在逐行导航它。所以我们正在查看的对象是一个名为rowCSV::Row

这是我尝试导航 row 时发生的屏幕截图: screenshot

如您所见,我可以致电 .headers(),正如您所料,Strain 在列表中

当您查看对象本身时,您会看到"Strain":"818 Headband"

所以row['Strain'] 应该等于8181 Headband 除非它返回nil

当然,我尝试了row.Strainrow["Strain"]row[Strain]row[:Strain],但都没有奏效。

我还认为它可能包含在一个单项数组中,所以我尝试了row[0]['Strain'],结果也返回了nil,这并不奇怪。

假设问题出在CSV::Row 对象上,我调用了row_hash = row.to_hash() 来获取该对象作为哈希值。

既然我们在基本的 ruby​​ 中,当然像 row_hash['Strain'] 这样的普通调用会正常工作吗?!?没有。还是nila view of row_hash

我很困惑,这根本不是复杂的代码。 HashCSV::Row 的文档都将[] 列为一种方法,而我在谷歌上搜索的所有文章都将row['key'] 列为正确的格式……除非它对我不起作用。

请帮忙,我有一系列这些 csv,我需要用这些 csv 来作为数据库的种子,如果我无法导航哈希,我就无法这样做!

编辑 2018 年 5 月 15 日下午 12:51:

csv.each do |row|
  row.each do |key, value|
    binding.pry
  end
end

$ key
=> "Strain"
$ value
=> "818 Headband"
$ row["Strain"]
=> nil

这不可能……

2018 年 5 月 15 日下午 1:05 编辑:

$ = irb(main)

$ csv_text = File.read('strain_data_formatted.csv')
=> ... (it dumped the whole csv to console)
$ csv = CSV.parse(csv_text, :headers => true, :encoding => 'ISO-8859-1')
=> #<CSV::Table mode:col_or_row row_count:118>
$ csv.first
=> #<CSV::Row "Strain":"818 Headband" "Subspecies":nil "Heritage":nil... 
$ csv.first["Strain"]
=> nil
$ csv.headers.first
=> "Strain"
$ csv.first[csv.headers.first]
=> "818 Headband"
$ csv.headers.first.class
=> String
$ "Strain".class
=> String
$ csv.headers.first == "Strain"
=> false
$ csv.headers.first
=> "Strain"

csv.headers.first 是一个值为“Strain”的字符串,但它不等于一个值为“Strain”的字符串?!?

【问题讨论】:

  • row.has_key?("Strain") 的输出是什么。另外,您是否尝试过使用each 遍历该行,并且您可以打印出该行中每个元素的键值吗?看起来您的代码应该可以工作。您是否尝试过在没有 Rails 的常规 IRB 会话中解析 CSV?您的环境中可能有一些东西导致了奇怪
  • row[row.headers.first] 返回正确的结果吗? row.headers.first.bytes 看起来像什么? (也请将代码添加为文本(使用代码格式化按钮)而不是图像)
  • Leo - row.has_key?("Strain") 返回false 我很惊讶,我们可以将“应变”视为选项之一。我还没有尝试过对每个行进行迭代,我现在就试试。我也没有尝试过普通的 IRB,所以我也可以试试。 Lime - row[row.headers.first] 返回 "818 Headband" 令人惊讶,因为 row.headers.first 返回 "Strain"row["Strain"] 仍然返回 nil
  • @IanBrooks rows.headers.first.bytesrows.headers.first.codepoints 怎么样?这些会告诉你标题中是否有任何隐藏/不可见的字符。如果有,您需要 gsub 删除它们或删除原始 csv 中的文本并手动重新输入以确保没有添加任何额外内容

标签: ruby-on-rails ruby csv parsing hash


【解决方案1】:

Simple Lime 为我指明了正确的方向!谢谢!

问题是当标题打印为字符串时,隐藏的字符不会被渲染。这就是为什么csv.first[csv.headers.first] 有效但csv.first["Strain"] 无效,即使csv.headers.first 返回"Strain"。大概它真正返回的内容类似于"invisiblestuffStrain"(夸大了但你明白了)。

要检查您是否属于这种情况,请在标题上调用.bytes 方法,然后在您期望的字符串值上再次调用.bytes,例如"Strain".bytes。如果有任何区别,你有隐藏的字符。

这是我的实际控制台输出:

$ csv.headers.first.bytes
=> [239, 187, 191, 83, 116, 114, 97, 105, 110]
$ "Strain".bytes
=> [83, 116, 114, 97, 105, 110]

您可以看到为该对象存储了 3 个额外字符,这些字符在呈现为字符串时不会显示。

Simple Lime 说:“您需要 gsub 他们或删除原始 csv 中的文本并手动重新输入以确保没有添加任何额外内容”

对我来说,我必须直接从我的文本编辑器中修改 .csv,以便使用 excel 并将其保存为 .csv

编辑:我发现从 MS Excel 中的 .xlsx 工作簿保存到 .csv 是导致出现这些奇怪字符的原因。我不得不编辑文件,所以我重新打开并重新保存,并在重新播种时再次遇到同样的错误。和以前一样,从文本编辑器重新输入第一个标题可以解决问题。

【讨论】:

    【解决方案2】:

    可以使用gsub方法去除多余的不可见字符

    gsub("\xEF\xBB\xBF","")
    

    【讨论】:

      【解决方案3】:

      该文件包含UTF-8 BOM

      您可以通过多种方式删除它。查看How can I remove the BOM from a UTF-8 file?上的答案

      【讨论】:

      • 请不要只发布对其他 Stack Exchange 问题的链接答案。相反,请在此处包含答案的基本部分,并针对此特定问题定制答案。
      【解决方案4】:

      我以为我也遇到了你的问题,直到我意识到 Ruby 没有正确拆分列。我把我的解决方案放在这里,以防其他人陷入同样的​​境地。我需要添加的只是col_sep 属性,如下所示: CSV.parse('file_name', headers: true, encoding: 'ISO-8859-1', col_sep: ';')

      【讨论】:

        猜你喜欢
        • 2016-08-15
        • 2017-08-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多