【问题标题】:Stripping byte order mark from zip stream in ruby从 ruby​​ 中的 zip 流中剥离字节顺序标记
【发布时间】:2018-10-15 14:01:41
【问题描述】:

我知道 File 应该采用 encoding: 'bom|utf-8' 但因为流没有等价物。我的服务器正在获取一个 zip 文件,其中包含一个具有 bom 的 csv。将 csv 保存为文件而不是仅使用 CSV.new(Zip::InputStream::open(zip_file).get_next_entry.get_input_stream) 似乎很愚蠢,但是没有一个可以检测和剥离字节顺序标记(bom),如果 bom 存在,CSV 尝试解析标头失败。

我看到CSV.newencoding 作为一个选项,但至少在2.3.0 中,它无法识别bom (ArgumentError: unknown encoding name - bom)

【问题讨论】:

  • 应该是"BOM|UTF-8" 而不仅仅是"bom"
  • 当然,我尝试过这个以及所有不同的排列方式。
  • 获取Encoding.name_list 显示没有与bom 大小写不变量或子字符串有任何相似性的编码。我很好奇BOM 编码的来源。

标签: ruby csv encoding inputstream


【解决方案1】:

看起来处理 BOM 是在 IO 中实现的 - 也许您可以将 zip 流包装在 IO 对象周围?

https://ruby-doc.org/core-2.3.1/IO.html#method-c-new-label-Open+Mode

【讨论】:

  • 谢谢!唉,IO#new 不接受 Zip::InputStream 作为 fd,但这至少解释了 BOM 的定义位置! > io = IO.new(stream, 'r:BOM|UTF-8') TypeError: no implicit conversion of Zip::InputStream into Integer
  • 如何将 IO 传递到 zip 流中?基本上你想首先通过 IO 运行它来处理编码,然后将它传递到 zip 流中解压缩,最后但并非最不重要的是使用 CSV 库读取它 - CSV.new(Zip::InputStream::open(IO.open(zip_file, 'r:BOM|UTF-8')).get_next_entry.get_input_stream)
  • 我相信 zip 文件没有 bom,但 zip 中的文件有;所以,这是行不通的,实际上可能会收到误报。
  • 那么在这种情况下,您可能会将 zip 中的流包装到另一个 IO 流中? stream_with_bom = Zip::InputStream::open(zip_file).get_next_entry.get_input_stream 然后CSV.new IO.open(stream_with_bom, 'r:BOM|UTF-8')
  • 如果您可以上传示例文件,我可以尝试实际运行代码
【解决方案2】:

由于您可以倒带流,答案是获取第一个字符,看看它们是否是 bom,如果是,则使用它们;否则,倒回流。

BYTE_ORDER_MARKS_LENGTHS =
  {"\xEF".bytes.first => 2, "\xFE".bytes.first => 1, "\xFF".bytes.first => 1}
# checks if input_stream starts with a byte order mark and if so skips over it
def skip_bom(input_stream)
  entry = BYTE_ORDER_MARKS_LENGTHS[input_stream.read(1).bytes.first]
  if entry
    input_stream.read(entry)
  else
    input_stream.rewind
  end
end

【讨论】:

    【解决方案3】:

    我的情况类似,但我还需要删除多余的双引号:

    Zip::File.open(zipfolder) do |zipfile|
      zipfile.each do |zip_entry|
        zip_entry.get_input_stream.each_line do |line|
          line_without_bom_or_quotes = line.force_encoding('UTF-8').gsub('"', '')
          row = CSV.parse_line(line_without_bom_or_quotes)
          puts "DETAIL: #{row.inspect}"
        end
      end
    end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-09-22
      • 2011-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多