当我们导入csv数据时,如何消除“UTF-8中的无效字节序列”

时间:2011-02-19 20:07:24

标签: ruby utf-8

我们允许用户通过csv导入数据(使用ruby 1.9.2,因此它的速度更快)。

当然,用户数据可能无法正确消毒。

当我们尝试在/ index方法中显示数据时,我们有时会得到错误“UTF-8中的无效字节序列”指向我们的erb,其中我们显示了一个字段widget.name

当我们进行导入时,我们希望强制传入的数据有效...是否有一个ruby运算符,它将字符串映射到有效的utf8字符串,例如

goodstring = badstring.no_more_invalid_bytes

“坏”数据的一个例子是char,它看起来像连字符,但不是常规的ascii连字符。我们更喜欢将非utf-8字符映射到一个合理的ascii等效字符(umlat-u to to u to exmaple)但是我们可以简单地将字符剥离到。

因为这是在导入大量数据时,它需要是一个快速的内置运算符,希望...


注意:这是一个数据示例。该文件来自窗口,是8位ascii。当我们导入它并在我们的erb中我们显示widget.name.inspect(而不是widget.name)时,我们得到: “链条\ x96配件”

所以数据的一个例子是“连字符”,它实际上是8位代码96。

---当我们改变我们的csv解析以指定fldval = d.encode('UTF-8') 它抛出了这个错误:

Encoding::UndefinedConversionError in StoresController#importfinderitems
"\x96" from ASCII-8BIT to UTF-8

我们正在寻找的是一种简单的方法,即使我们简单地剥离非ascii,也可以强制它无论原点类型是否有效,即使我们只是去除非ascii。


虽然不像强制编码那样'很好',但这对我们的导入时间来说有点费用: d.to_s.strip.gsub(/ \ P {ASCII} /,'') 谢谢,Mladen!

9 个答案:

答案 0 :(得分:119)

Ruby 1.9 CSV具有与m17n一起使用的新解析器。解析器使用字符串中的IO对象编码。以下方法:::foreach, ::open, ::read, and ::readlines可以接受可选项:encoding,您可以指定编码。

例如:

CSV.read('/path/to/file', :encoding => 'windows-1251:utf-8')

将所有字符串转换为UTF-8。

您还可以使用更标准的编码名称“ISO-8859-1”

CSV.read('/..', {:headers => true, :col_sep => ';', :encoding => 'ISO-8859-1'})

答案 1 :(得分:13)

我回答了一个类似的问题,涉及使用非UTF-8编码读取1.9.2中的外部文件。我认为这个答案会对你有所帮助:Character Encoding issue in Rails v3/Ruby 1.9.2

请注意,您需要知道源编码才能将其转换为可靠的。在我的另一个答案中,有一些库可以帮助您确定这个库。

另外,如果您没有从文件加载数据,您可以很容易地转换1.9.2中字符串的编码:

'string'.encode('UTF-8')

但是,您很少使用其他编码构建字符串,如果可能的话,最好在将其读入您的环境时对其进行转换。

答案 2 :(得分:10)

CSV.parse(File.read('/path/to/csv').scrub)

答案 3 :(得分:7)

Ruby 1.9可以使用无效的检测和替换来更改字符串编码:

str = str.encode('UTF-8', :invalid => :replace)

对于异常字符串,例如从未知编码文件加载的字符串,使用#encode而不是正则表达式,#gsub或#delete是明智的,因为这些都需要解析字符串 - 但是如果字符串被破坏了,无法解析,所以这些方法都失败了。

如果你收到这样的消息:

error ** from ASCII-8BIT to UTF-8

然后你可能试图转换已经是UTF-8的二进制字符串,你可以强制使用UTF-8:

str.force_encoding('UTF-8')

如果你知道原始字符串不是二进制UTF-8,或者输出字符串有非法字符,那么请阅读Ruby编码音译。

答案 4 :(得分:4)

如果您使用 Rails ,可以尝试使用以下

修复它
'Your string with strange stuff #@~'.mb_chars.tidy_bytes

它会删除无效的utf-8字符,并将其替换为有效字符。 更多信息:https://apidock.com/rails/String/mb_chars

答案 5 :(得分:2)

我正在使用MAC,但遇到相同的错误:

rescue in parse:Invalid byte sequence in UTF-8 in line 1 (CSV::MalformedCSVError)

我添加了:encoding => 'ISO-8859-1'来解决我的错误,并且可以读取csv文件。


results = CSV.read("query_result.csv",{:headers => true, :encoding => 'ISO-8859-1'})

:headers => true:如果设置为:first_row或true,则CSV文件的初始行将被视为标题行。如果设置为Array,则其内容将用作标题。如果将其设置为String,则通过与该实例相同的:col_sep,:row_sep和:quote_char的:: parse_line调用来运行该字符串,以生成标头数组。此设置导致#shift将行作为CSV :: Row对象而不是数组返回,并且#read将返回CSV :: Table对象而不是数组Array。

irb(main):024:0> rows = CSV.new(StringIO.new("a,b,c\n1,2,3"), headers: true)
=> <#CSV io_type:StringIO encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"" headers:true>
irb(main):025:0> rows = CSV.new(StringIO.new("a,b,c\n1,2,3"), headers: true).to_a
=> [#<CSV::Row "a":"1" "b":"2" "c":"3">]
irb(main):026:0> rows.first['a']
=> "1"

在上面的示例中,您可以清楚地看到,这也使我们能够将数据用作哈希。 使用headers: true时,您唯一需要注意的是,它不允许任何重复的标头,因为键在哈希中是唯一的。

答案 6 :(得分:1)

将CSV文件上传到Google文档电子表格,然后将其重新下载为CSV文件。进口,瞧! (在我的情况下工作)

据推测,谷歌会将其转换为想要的格式..

来源:Excel to CSV with UTF-8 Encoding

答案 7 :(得分:0)

只做这个

anyobject.to_csv(:encoding => 'utf-8')

答案 8 :(得分:0)

正如其他人所说,在Ruby 2.1+中,scrub可以很好地清理它。如果您有一个大文件,您可能不想将整个内容读入内存,因此您可以像这样使用scrub:

TLSv1.2