Ruby 如何使用:replace、:invalid和:undef参数来使用CSV.read进行编码?

Ruby 如何使用:replace、:invalid和:undef参数来使用CSV.read进行编码?,ruby,csv,encoding,Ruby,Csv,Encoding,由于ruby 1.9,CSV使用可以执行编码的解析器,如果您使用以下方法: ::foreach、::open、::read和::readlines 例如:CSV.read('path/to/file',encoding:“windows-1252:UTF-8”)尝试读取windows-1252中的文件,并返回一个带有UTF-8编码字符串的数组 如果字符集之间的编码转换包含未定义的字符,则会给出一个编码::UndefinedConversionError String.encode方法有一些很好的

由于ruby 1.9,CSV使用可以执行编码的解析器,如果您使用以下方法:
::foreach、::open、::read和::readlines

例如:
CSV.read('path/to/file',encoding:“windows-1252:UTF-8”)
尝试读取windows-1252中的文件,并返回一个带有UTF-8编码字符串的数组

如果字符集之间的编码转换包含未定义的字符,则会给出一个
编码::UndefinedConversionError

String.encode方法有一些很好的参数来处理这些未定义的字符:

str=str.encode('UTF-8',无效::替换,未定义::替换,替换:“”)

有没有一种方法可以使用这种替换规则在CSV解析器的字符集之间进行未定义的转换


谢谢。

如果您想使用String#encode的替换行为,您必须使用它对整个文件内容进行编码,或者逐行进行编码您将因此丢失信息。

但这是一种方法:

file = File.open('path/to/file.csv')
file.each do |line|
  # keep in mind that the first parameter here is the destination encoding,
  # the second is the source encoding
  sanitized_line = line.encode('UTF-8', 'windows-1252', invalid: :replace, undef: :replace, replace: '')
  fields_array = CSV.parse_line(sanitized_line)
  # do whatever you want with the fields you extracted
end
如果从一种编码到另一种编码的转换几乎可以保证不会丢失信息(例如iso-8859-1到utf-8),我真的建议您在读取时简单地转换文件

要记住的另一件事是,ruby不会试图自己找出正在读取的文件的编码。如果省略该参数,它将仅使用其外部和内部编码的默认编码。因此,您必须自己指定文件的编码。Ruby没有真正可靠的方法来实现这一点,所以在我的例子中,我最终做到了(在Ubuntu系统上):


的确,有一种方法。诀窍是定义一个自定义转换器,它使用
String#encode
执行您想要的转换。转换器在CSV尝试自动转换为UTF-8之前运行。我们将自定义转换器传递给
CSV。读取
:converters
选项以及原始
:encoding

UTF8_CONVERTER = ->(field) { field.encode('utf-8', invalid: :replace, undef: :replace, replace: "") }

CSV.read('foo.csv', encoding: 'windows-1252', converters: UTF8_CONVERTER)
由于Windows-1252中没有任何字符不在UTF-8中,因此我将以另一种方式演示。假设您有这个UTF-8 CSV文件:

foo,bar

是的还有一点需要注意的是,如果任何字段包含换行符(在引用的字段中有效),则此操作将失败。此解决方案有效。我发现乔丹的一个更完整。谢谢。KMoschcau解决方案也可以使用。我之所以选择这个,是因为我发现将转换器定义为过程更为完整。
UTF8_CONVERTER = ->(field) { field.encode('utf-8', invalid: :replace, undef: :replace, replace: "") }

CSV.read('foo.csv', encoding: 'windows-1252', converters: UTF8_CONVERTER)