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



我使用的是ruby 1.9.2

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

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

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

元素返回为ASCII-8BIT编码的字符串(sp cifi变成spxE9cifixE9),然后像"sp cifi"这样的字符串不能正确保存到我的MySQL数据库中。

Yehuda Katz说ASCII-8BIT实际上是"二进制"数据,这意味着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的字符串,它看起来像"Non spxE9cifixE9"而不是"Non sp cifi"。

通过这样做,我无法将"Non spxE9cifixE9"转换为"Non sp cifi""Non spxE9cifixE9".encode("UTF-8")

因为我得到了这个错误:

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

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

问题:

  1. 我可以得到CSV读取我的文件在适当的编码?如果有,怎么做?
  2. 我如何将ASCII-8BIT字符串转换为UTF-8以在MySQL中进行适当的存储?

decze是对的,即ISO8859-1(又名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 spxE9cifixE9",那么utf8_string将是"Non spécifié"。此外,Iconv.iconv可以一次解整整个数组:

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

对于较新的ruby,您可以这样做:

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

latin1_string认为它是ASCII-8BIT,但实际上是ISO-8859-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"
  )

我已经处理这个问题有一段时间了,但没有任何其他解决方案对我有效。

这个技巧是将冲突的字符串存储在一个二进制文件中,然后正常读取该文件,并使用这个字符串为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)

相关内容

  • 没有找到相关文章

最新更新