我使用的是ruby 1.9.2
我正在尝试解析一个CSV文件,其中包含一些法语单词(例如sp
当我从CSV文件中读取这些行时,
file_contents = CSV.read("csvfile.csv", col_sep: "$")
元素返回为ASCII-8BIT编码的字符串(sp
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
通过这样做,我无法将"Non spxE9cifixE9"转换为"Non sp"Non spxE9cifixE9".encode("UTF-8")
因为我得到了这个错误:
Encoding::UndefinedConversionError: "xE9" from ASCII-8BIT to UTF-8
,
Katz指出会发生这种情况,因为ASCII-8BIT并不是真正合适的字符串"编码"。
问题:
- 我可以得到CSV读取我的文件在适当的编码?如果有,怎么做?
- 我如何将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)