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

我们允许用户通过 csv 导入数据(使用 ruby 1.9.2,因此它是 fastercsv)。

当然,作为用户数据,它可能没有被正确地消毒。

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

当我们进行导入时,我们想要强制输入的数据是有效的... 是否有一个 Ruby 操作符将一个字符串映射到一个有效的 utf8字符串,例如

goodstring = badstring.no_more_invalid_bytes

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

因为这是当导入大量数据时,它需要一个快速的内置操作符,希望..。


注意: 下面是一个数据示例。这个文件来自 windows,是8位 ascii。当我们导入它时,在 erb 中我们显示 widget.name.sight (而不是 widget.name) ,我们得到: “锁链 x96配件”

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

——-当我们将 csv 解析器改为分配 fldval = d.encode (‘ UTF-8’)时 它抛出了这个错误:

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

我们要找的是一种简单的方法,强制它是有效的 utf8不管原点类型是什么,即使我们只是去掉 non-ascii。


虽然不像强制编码那么“好”,但这样做会稍微减少导入时间: (/P { ASCII }/,”) 谢谢你,穆拉登!

59346 次浏览

我回答了一个类似的问题,即在1.9.2中使用非 UTF-8编码读取外部文件。我认为这个答案会对你有很大帮助: Rails v3/Ruby 1.9.2中的字符编码问题

请注意,您需要知道源代码,以便可靠地转换它。有一些类似于我在另一个答案中所链接的库可以帮助您确定这一点。

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

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

但是,很少用另一种编码方式构建字符串,如果可能的话,最好在将其读入环境时进行转换。

Ruby 1.9可以通过无效检测和替换改变字符串编码:

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

对于不常见的字符串,比如从未知编码的文件中加载的字符串,明智的做法是使用 # encode 而不是 regex、 # gsub 或 # delete,因为这些都需要解析字符串——但是如果字符串中断了,就不能解析它,所以这些方法会失败。

如果你收到这样的信息:

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

然后,您可能尝试转换一个已经使用 UTF-8的二进制字符串,您可以强制使用 UTF-8:

str.force_encoding('UTF-8')

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

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'})

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

据推测,谷歌将其转换为所需的格式. 。

资料来源: 用 UTF-8编码 Excel 到 CSV

只能这么做

anyobject.to_csv(:encoding => 'utf-8')
CSV.parse(File.read('/path/to/csv').scrub)

如果您正在使用 铁路,可以尝试使用以下方法修复它

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

它删除无效的 utf-8字符并用有效的字符替换它。 更多信息: < a href = “ https://apidock.com/ails/String/mb _ chars”rel = “ norefrer”> https://apidock.com/rails/string/mb_chars

正如其他人所提到的,在 Ruby 2.1 + 中,矬子可以很好地清理这个问题。如果你有一个很大的文件,你可能不想把整个文件读入内存,所以你可以使用这样的擦洗:

data = IO::read(file_path).scrub("")
CSV.parse(data, :col_sep => ',', :headers => true)  do |row|
puts row
end

我正在使用 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,则通过调用与此实例相同的: colsep、 : row _ sep 和: quote _ char: : parse _ line 来运行 String,以生成一个数组头文件。这个设置导致 # shift 将返回行作为 CSV: : Row 对象而不是 Array,并且 # 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时唯一需要注意的是,它不允许任何重复的标头,因为键在散列中是唯一的。