由于红宝石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解析器的字符集之间使用这种替换规则进行未定义的转换?
谢谢.
确实有一种方法.诀窍是定义一个自定义转换器,用于执行您想要的转换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是默认设置,但如果您的文件具有不同的编码,则必须使用.)