如何使用:replace,:invalid和:undef args使用CSV.read进行编码?

And*_*s M 4 ruby csv encoding

由于红宝石1.9,CSV使用可以进行编码,如果你使用的方法,如解析器: ::foreach, ::open, ::read, and ::readlines.

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

如果字符集之间的编码转换有未定义的字符,则给出一个Encoding::UndefinedConversionError.

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

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

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

谢谢.

Jor*_*ing 5

确实有一种方法.诀窍是定义一个自定义转换器,用于执行您想要的转换String#encode.转换器在CSV尝试自动转换为UTF-8之前运行.我们将自定义转换器CSV.read作为:converters选项与原始转换器一起传递:encoding:

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

CSV.read('foo.csv', encoding: 'windows-1252', converters: UTF8_CONVERTER)
Run Code Online (Sandbox Code Playgroud)

由于Windows-1252中没有任何字符也不是UTF-8,我将演示相反的方法.假设您有此UTF-8 CSV文件:

foo,bar
yes,no
Run Code Online (Sandbox Code Playgroud)

并且假设我想将其转换为ASCII-8BIT(因为原因?).这给了我一个错误:

CSV.read('emoji.csv', encoding: 'utf-8:ascii-8bit')
# => Encoding::UndefinedConversionError: U+1F44D from UTF-8 to ASCII-8BIT
Run Code Online (Sandbox Code Playgroud)

但是,如果我定义一个替换那些未定义字符的自定义转换器,它可以完美地工作:

ASCII_CONVERTER = ->(field) { field.encode('ascii-8bit', replace: "@") }

CSV.read('emoji.csv', encoding: 'utf-8', converters: ASCII_CONVERTER)
# => [ [ "foo",  "bar"   ],
#      [ "yes@", "no@"] ]
Run Code Online (Sandbox Code Playgroud)

(请注意,encoding: 'utf-8'此处并非严格必要,因为UTF-8是默认设置,但如果您的文件具有不同的编码,则必须使用.)