字符串-Ruby读取CSV文件为UTF-8和/或将ASCII-8Bit编码转换为UTF-8

我正在使用ruby 1.9.2

我正在尝试解析一个包含一些法语单词(例如spécifié)的CSV文件,并将其内容放置在MySQL数据库中。

当我从CSV文件中读取行时,

file_contents = CSV.read("csvfile.csv", col_sep: "$")

元素以ASCII-8BIT编码的字符串形式返回(spécifié变为sp \ xE9cifi \ xE9),然后诸如“spécifié”之类的字符串未正确保存到我的MySQL数据库中。

Yehuda Katz说ASCII-8BIT实际上是“二进制”数据,这意味着CSV不知道如何读取适当的编码。

因此,如果我尝试使CSV强制如下编码:

Encoding::UndefinedConversionError: "\xE9" from ASCII-8BIT to UTF-8

我收到以下错误

ArgumentError: invalid byte sequence in UTF-8: 

如果我回到原始的ASCII-8BIT编码字符串,然后检查CSV读取为ASCII-8BIT的字符串,则它看起来像是“ Non sp \ xE9cifi \ xE9”而不是“ Nonspécifié”。

我无法将“ Non sp \ xE9cifi \ xE9”转换为“ Nonspécifié”Encoding::UndefinedConversionError: "\xE9" from ASCII-8BIT to UTF-8

因为我得到这个错误:

Encoding::UndefinedConversionError: "\xE9" from ASCII-8BIT to UTF-8

Katz指出会发生这种情况,因为ASCII-8BIT并不是真正的字符串“编码”。

问题:

  1. 我可以获取CSV格式的文件来读取我的文件吗? 如果是这样,怎么办?
  2. 如何将ASCII-8BIT字符串转换为UTF-8以便在MySQL中正确存储?
user141146 asked 2020-01-13T14:02:20Z
3个解决方案
58 votes

deceze是正确的,即ISO8859-1(AKA Latin-1)编码的文本。 尝试这个:

file_contents = CSV.read("csvfile.csv", col_sep: "$", encoding: "ISO8859-1")

如果那行不通,您可以使用latin1_string来修复单个字符串,如下所示:

require 'iconv'
utf8_string = Iconv.iconv('utf-8', 'iso8859-1', latin1_string).first

如果latin1_string"Non sp\xE9cifi\xE9",那么utf8_string将是"Non spécifié"。而且,Iconv.iconv可以一次解开整个阵列:

utf8_strings = Iconv.iconv('utf-8', 'iso8859-1', *latin1_strings)

使用更新的红宝石,您可以执行以下操作:

utf8_string = latin1_string.force_encoding('iso-8859-1').encode('utf-8')

latin1_string认为它是ASCII-8BIT,但实际上是ISO-8859-1。

mu is too short answered 2020-01-13T14:03:00Z
26 votes

当红宝石> = 1.9时,您可以使用

file_contents = CSV.read("csvfile.csv", col_sep: "$", encoding: "ISO8859-1:utf-8")

ISO8859-1:utf-8的含义是:csv文件是ISO8859-1-编码,但是将内容转换为utf-8

如果您希望使用更详细的代码,则可以使用:

file_contents = CSV.read("csvfile.csv", col_sep: "$", 
    external_encoding: "ISO8859-1", 
    internal_encoding: "utf-8"
  )
knut answered 2020-01-13T14:03:28Z
1 votes

我已经处理了一段时间,没有其他解决方案对我有用。

导致问题的方法是将冲突字符串存储在二进制文件中,然后正常读取文件并使用此字符串来馈送CSV模块:

tempfile = Tempfile.new("conflictive_string")
tempfile.binmode
tempfile.write(conflictive_string)
tempfile.close
cleaned_string = File.read(tempfile.path)
File.delete(tempfile.path)
csv = CSV.new(cleaned_string)
fguillen answered 2020-01-13T14:03:53Z
translate from https://stackoverflow.com:/questions/7047944/ruby-read-csv-file-as-utf-8-and-or-convert-ascii-8bit-encoding-to-utf-8