更改字符编码

5

我在Ruby 1.9.2p290中更改文本文件的编码时遇到了问题。我得到了错误"invalid byte sequence in UTF-8 (ArgumentError)"。问题(我认为)在于字符集似乎是未知的。

如果我从命令行执行以下操作:

$ file test.txt

I get:

Non-ISO extended-ASCII English text, with CRLF line terminators

或者,作为替代方案,如果我执行:

$ file -i test.txt 

I get:

test.txt: text/plain; charset=unknown

然而,在 Ruby 中,如果我执行以下操作:

data = File.open("test.txt").read

puts data.encoding.name

puts data.valid_encoding?

我能理解:

UTF-8
false

这是我代码的简化片段:

以下是简化后的代码:

data = File.open("test.txt").read

data.encode!("UTF-8")

data.each_line do |line|

  newfile_data << line

end

文件中是否包含任何花哨的字符?您是如何创建该文件/以什么格式保存的? - deceze
2个回答

9
在Ruby 1.9中,每个流都有两个编码与之关联 - 外部编码和内部编码。外部编码是从流(在您的情况下为文件)中读取的文本的编码。内部编码是所读取文件的文本的期望编码。
如果您没有为流设置外部/内部编码,则将使用进程的默认外部/内部编码。如果未指定内部编码,则从流中读取的字符串将被标记(而不是转换)为外部编码(与 String.force_encoding 相同)。
很可能您有…
Encoding::default_external # => Encoding:UTF-8
Encoding::default_internal # => nil

您的文件使用基于ASCII的标准字符编码进行编码,而不是UTF-8。您的Ruby代码将字节序列从外部源读入UTF-8字符串中。由于字符串包含非ISO扩展ASCII英文文本,因此您会得到data.valid_encoding? # => false

您需要将流的外部编码设置为文件的编码。例如,如果您有一个使用cp 1251编码并带有文本файл的文件,则需要使用以下代码来读取它:

data = File.open("test.txt", 'r:windows-1251').read    
puts data.encoding.name    # => windows-1251
puts data.valid_encoding?  # => true

或者甚至可以同时指定内部和外部编码:

data = File.open("test.txt", 'r:windows-1251:utf-8').read    
puts data.encoding.name    # => utf-8
puts data.valid_encoding?  # => true

3
data = IO.read("test.txt", :encoding => 'windows-1252')
data = data.encode("UTF-8").gsub("\r\n", "\n")

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接