我们允许用户通过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!
答案 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文件。进口,瞧! (在我的情况下工作)
据推测,谷歌会将其转换为想要的格式..
答案 7 :(得分:0)
只做这个
anyobject.to_csv(:encoding => 'utf-8')
答案 8 :(得分:0)
正如其他人所说,在Ruby 2.1+中,scrub可以很好地清理它。如果您有一个大文件,您可能不想将整个内容读入内存,因此您可以像这样使用scrub:
TLSv1.2