首页 文章

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

提问于
浏览
49

我正在使用ruby 1.9.2

我正在尝试 parse a CSV file ,其中包含一些法语单词(例如spécifié)并将内容放在MySQL数据库中 .

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

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

这些元素作为 ASCII-8BIT 编码的字符串返回(spécifié变为sp \ xE9cifi \ xE9),然后像"spécifié"这样的字符串未正确保存到我的MySQL数据库中 .

Yehuda Katz说ASCII-8BIT实际上是"binary"数据意味着CSV不知道如何读取适当的编码 .

所以,如果我尝试使CSV强制编码如下:

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

我收到以下错误

ArgumentError: invalid byte sequence in UTF-8:

如果我回到我原来的ASCII-8BIT编码字符串并检查我的CSV读取为ASCII-8BIT的字符串,它看起来像“非sp \ xE9cifi \ xE9”而不是“非spécifié” .

我不能通过这样做将"Non sp\xE9cifi\xE9"转换为"Non spécifié" "Non sp\xE9cifi\xE9".encode("UTF-8")

因为我收到这个错误:

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

Katz指出会发生这种情况,因为ASCII-8BIT实际上不是一个正确的字符串“编码” .

Questions:

  • Can I get CSV to read my file in the appropriate encoding? If so, how?

  • How do I convert an ASCII-8BIT string to UTF-8 for proper storage in MySQL?

3 回答

  • 53

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

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

    如果这不起作用,您可以使用Iconv来修复单个字符串,如下所示:

    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)
    

    使用较新的Rubies,您可以执行以下操作:

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

    latin1_string 认为它在ASCII-8BIT中,但实际上在ISO-8859-1中 .

  • 1

    使用ruby> = 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"
      )
    
  • 23

    我一直在处理这个问题,而不是任何其他解决方案对我有用 .

    制作技巧的方法是将冲突字符串存储在二进制文件中,然后正常读取文件并使用此字符串来提供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)
    

相关问题