when we import csv data, how eliminate “invalid byte sequence in UTF-8”
我们允许用户通过csv导入数据(使用Ruby1.9.2,因此它是fastercsv)。
当然,作为用户数据,它可能没有被正确地清理。
当我们试图以/index方法显示数据时,有时会得到一个错误"invalid byte sequence in utf-8"(以UTF-8表示的字节序列无效),指向我们的erb,在这里我们显示一个字段widget.name。
当我们进行导入时,我们希望强制输入的数据有效…是否有Ruby运算符将字符串映射到有效的utf8字符串,例如
1 | goodstring = badstring.no_more_invalid_bytes |
"坏"数据的一个例子是char,它看起来像连字符,但不是常规的ASCII连字符。我们更愿意将非UTF-8字符映射为一个合理的ASCII等价字符(umlat-u将u用于exmaple),但我们可以简单地将字符剥离为。
因为这是在导入大量数据时,它需要一个快速的内置操作符,希望…
注意:这里是一个数据示例。该文件来自Windows,是8bit ASCII。当我们导入它时,在erb中显示widget.name.inspect(而不是widget.name),我们得到:"链条x96附件"
所以数据的一个例子是"连字符",实际上是8位代码96。
---当我们将csv解析改为分配fldval=d.encode时("utf-8")。它引发此错误:
1 2 | Encoding::UndefinedConversionError in StoresController#importfinderitems "\x96" from ASCII-8BIT to UTF-8 |
我们要寻找的是一种简单的方法,可以强制它成为有效的utf8,而不管源类型是什么,即使我们只是简单地去掉非ascii。
虽然没有强制编码那么"好",但这对我们的导入时间来说是一个很小的开销:d.to_s.strip.gsub(/p ascii/,'')谢谢你,米亚丁!
Ruby1.9csv有了新的解析器,可以与m17n一起使用。解析器可以对字符串中的IO对象进行编码。以下方法:
例如:
1 | CSV.read('/path/to/file', :encoding => 'windows-1251:utf-8') |
将所有字符串转换为UTF-8。
也可以使用更标准的编码名称"ISO-8859-1"
1 | CSV.read('/..', {:headers => true, :col_sep => ';', :encoding => 'ISO-8859-1'}) |
我回答了一个类似的问题,该问题涉及使用非UTF-8编码读取1.9.2中的外部文件。我认为这个答案对您有很大帮助:Railsv3/Ruby1.9.2中的字符编码问题
请注意,您需要知道源代码才能可靠地转换它。在我的另一个答案中,有一些库与我链接的库类似,可以帮助您确定这一点。
此外,如果不从文件加载数据,则可以很容易地转换1.9.2中字符串的编码:
1 | 'string'.encode('UTF-8') |
然而,很少有人用另一种编码构建字符串,如果可能的话,最好在将其读取到环境中时将其转换为字符串。
1 | CSV.parse(File.read('/path/to/csv').scrub) |
Ruby1.9可以通过无效的检测和替换来更改字符串编码:
1 | str = str.encode('UTF-8', :invalid => :replace) |
对于不寻常的字符串,例如从未知编码的文件加载的字符串,使用encode而不是regex、gsub或delete是明智的,因为这些都需要解析字符串——但是如果字符串断开,就无法解析,因此这些方法会失败。
如果您收到这样的消息:
1 | error ** from ASCII-8BIT to UTF-8 |
然后,您可能正在尝试转换一个已经是UTF-8格式的二进制字符串,您可以强制使用UTF-8:
1 | str.force_encoding('UTF-8') |
如果您知道原始字符串不是二进制的UTF-8,或者输出字符串有无数个字符,那么请阅读Ruby编码音译。
如果您使用的是Rails,可以尝试使用以下方法修复它
1 | 'Your string with strange stuff #@~'.mb_chars.tidy_bytes |
它将删除无效的UTF-8字符,并将其替换为有效字符。更多信息:https://apidock.com/rails/string/mbchars
将csv文件上传至google docs电子表格,并重新下载为csv文件。进口,瞧!(在我的案例中工作过)
大概谷歌会把它转换成想要的格式。
来源:Excel到CSV,采用UTF-8编码
正如其他人所提到的,Scrub在Ruby2.1+中很好地清理了这个问题。如果您有一个大文件,您可能不想将整个文件读取到内存中,因此您可以使用如下擦除:
1 2 3 4 | data = IO::read(file_path).scrub("") CSV.parse(data, :col_sep => ',', :headers => true) do |row| puts row end |
只做这个
1 | anyobject.to_csv(:encoding => 'utf-8') |