Ruby无法将字符串编码从ISO-8859-1转换为UTF-8

Ruby无法将字符串编码从ISO-8859-1转换为UTF-8,ruby,encoding,utf-8,character-encoding,iconv,Ruby,Encoding,Utf 8,Character Encoding,Iconv,我正在尝试将一个字符串从ISO-8859-1编码转换为UTF-8,但似乎无法正常工作。下面是我在irb中所做的一个例子 irb(main):050:0> string = 'Norrlandsvägen' => "Norrlandsvägen" irb(main):051:0> string.force_encoding('iso-8859-1') => "Norrlandsv\xC3\xA4gen" irb(main):052:0> string = string

我正在尝试将一个字符串从ISO-8859-1编码转换为UTF-8,但似乎无法正常工作。下面是我在irb中所做的一个例子

irb(main):050:0> string = 'Norrlandsvägen'
=> "Norrlandsvägen"
irb(main):051:0> string.force_encoding('iso-8859-1')
=> "Norrlandsv\xC3\xA4gen"
irb(main):052:0> string = string.encode('utf-8')
=> "Norrlandsvägen" 
我不知道为什么iso-8859-1中的Norrlandsvägen将转换为utf-8中的NorrlandsvÃgen

我试过编码,编码!,编码(destinationEncoding,originalEncoding),iconv,force_编码,以及我能想到的各种奇怪的工作方法,但似乎都不起作用。有人能帮我/给我指出正确的方向吗

Ruby新手仍然疯狂地拉扯着头发,但对这里所有的回复感到感激…:)

这个问题的背景:我正在编写一个gem,它将从一些网站下载一个xml文件(将采用iso-8859-1编码),并将其保存在一个存储器中,我想首先将其转换为utf-8。但是像诺兰兹瓦根这样的词总是把我弄糊涂。真的非常感谢您的帮助

[更新]:我意识到在irb控制台中运行这样的测试可能会给我带来不同的行为,因此我在实际代码中有以下内容:

def convert_encoding(string, originalEncoding) 
  puts "#{string.encoding}" # ASCII-8BIT
  string.encode(originalEncoding)
  puts "#{string.encoding}" # still ASCII-8BIT
  string.encode!('utf-8')
end
但最后一行给了我以下错误:

Encoding::UndefinedConversionError - "\xC3" from ASCII-8BIT to UTF-8
感谢@Amadan下面的回答,我注意到如果您运行以下命令,
\xC3
实际上会显示在irb中:

irb(main):001:0> string = 'ä'
=> "ä"
irb(main):002:0> string.force_encoding('iso-8859-1')
=> "\xC3\xA4"
我还尝试为
string.encode(originalEncoding)
的结果分配一个新变量,但得到了一个更奇怪的错误:

newString = string.encode(originalEncoding)
puts "#{newString.encoding}" # can't even get to this line...
newString.encode!('utf-8')
在从ASCII-8BIT到UTF-8再到ISO-8859-1的转换过程中,错误为
Encoding::UnfinedConversionError-“\xC3”到UTF-8


我仍然沉浸在编码的混乱中,但我真的很感谢所有人给我的回复和帮助!非常感谢!:)

在UTF-8中指定一个字符串。它包含
ä
。UTF-8用两个字节表示
ä

string = 'ä'
string.encoding
# => #<Encoding:UTF-8>
string.length
# 1
string.bytes
# [195, 164]
然后将其转换为
UTF-8
。因为这不是重新解释,而是翻译,所以保留这两个字符,但现在以UTF-8编码:

string = string.encode('utf-8')
# => "ä" 
string.length
# 2
string.bytes
# [195, 131, 194, 164]
您缺少的是一个事实,即您最初没有ISO-8859-1字符串,就像您从Web服务获得的一样—您有胡言乱语。幸运的是,这些都在您的控制台测试中;如果您使用正确的输入编码阅读网站的响应,那么应该一切正常

对于您的控制台测试,让我们演示一下,如果您从一个正确的ISO-8859-1字符串开始,它将全部工作:

string = 'Norrlandsvägen'.encode('iso-8859-1')
# => "Norrlandsv\xE4gen"
string = string.encode('utf-8')
# => "Norrlandsvägen"
编辑对于您的特定问题,这应该可以:

require 'net/https'
uri = URI.parse("https://rusta.easycruit.com/intranet/careerbuilder_se/export/xml/full")
options = {
  :use_ssl => uri.scheme == 'https', 
  :verify_mode => OpenSSL::SSL::VERIFY_NONE
}
response = Net::HTTP.start(uri.host, uri.port, options) do |https|
  https.request(Net::HTTP::Get.new(uri.path))
end
body = response.body.force_encoding('ISO-8859-1').encode('UTF-8')

和之间有区别。前者设置字符串的编码,而后者实际上将字符串的内容转换为新的编码。因此,以下代码会导致您的问题:

string = "Norrlandsvägen"
string.force_encoding('iso-8859-1')
puts string.encode('utf-8') # Norrlandsvägen
而以下代码实际上将正确编码您的内容:

string = "Norrlandsvägen".encode('iso-8859-1')
string.encode!('utf-8')
下面是一个在
irb
中运行的示例:

irb(main):023:0> string = "Norrlandsvägen".encode('iso-8859-1')
=> "Norrlandsv\xE4gen"
irb(main):024:0> string.encoding
=> #<Encoding:ISO-8859-1>
irb(main):025:0> string.encode!('utf-8')
=> "Norrlandsvägen"
irb(main):026:0> string.encoding
=> #<Encoding:UTF-8>
irb(main):023:0>string=“Norrlandsvägen”。编码('iso-8859-1'))
=>“Norrlandsv\xE4gen”
irb(主):024:0>string.encoding
=> #
irb(主):025:0>string.encode!('utf-8')
=>“Norrlandsvägen”
irb(主):026:0>string.encoding
=> #

上述答案非常准确。具体来说,这一点:


force_编码和encode之间有区别。前者 设置字符串的编码,而后者实际上 将字符串内容转换为新编码

在我的情况下,我有一个iso-8859-1编码的文本文件。默认情况下,Ruby使用UTF-8编码,因此如果您试图在不指定编码的情况下读取文件,则会出现错误:

results = File.read(file)
results.encoding
 => #<Encoding:UTF-8> 
 results.split("\r\n")
ArgumentError: invalid byte sequence in UTF-8
所以一切都很好,对吗?不,如果要开始解析具有UTF-8字符编码的iso-8859-1字符串,则不需要:

results = File.read(file, encoding: "iso-8859-1")
results.each do |line|
  puts line.split('¬')
end
Encoding::CompatibilityError: incompatible character encodings: ISO-8859-1 and UTF-8
为什么会出现这种错误?因为“,”表示为UTF-8。您正在对ISO-8859-1字符串使用UTF-8字符序列。它们是不兼容的编码。因此,在以ISO-8859-1的形式读取该文件后,可以要求Ruby将该ISO-8859-1编码为UTF-8。现在您将使用UTF-8字符串,因此没有问题:

results = File.read(file, encoding: "iso-8859-1").encode('UTF-8')
results.encoding
results = results.split("\r\n")
results.each do |line|
  puts line.split('¬')
end

最终,对于一些Ruby API,您不需要使用
force_编码('ISO-8859-1')
。相反,您只需指定API的预期编码。但是,如果您计划使用UTF-8字符串对其进行解析,则必须将其转换回UTF-8

哦,谢谢你!你说的很有道理,但不知怎的,当我从我的web服务中阅读时,Ruby实际上认为它是ASCII-8BIT,而不是ISO-8859-1。是我试图获取的xml的一个示例。我的代码是:
def convert\u encoding(string,originalEncoding)
string.encode(originalEncoding)
string.encode!('utf-8')
(中间有一些puts以显示字符串的编码和内容),但是我从ASCII-8BIT到utf-8得到了未定义的转换器“\xC3”我是否遗漏了一些明显的内容?您是如何从web服务读取XML的?顺便说一句,你链接到的文件是UTF-8,而不是ISO-8859-1,不管它自己声称什么。因此,文件中实际上有两个字节的UTF-8表示,第一个字节是
\xC3
;ASCII-8BIT->UTF-8转换阻塞了它。讽刺的是,您甚至不需要转换:)只要将流正确地作为UTF-8打开,或者在您读取它时将字符串强制为UTF-8即可。我使用
response=Net::HTTP.get_response(uri)
response.body
来获取xml。我好奇的是,如果我跳过编码转换步骤,将文件天真地保存在我的存储器(AWS S3)中并手动下载文件,我仍然会看到
“NorrlandsvÃgen”
,而不是
“Norrlandsvägen”
。您还可以教我如何识别文件的实际编码(不管其声明:)?要点是我一直在使用的一个简化示例;最后,我想得到一些文件,比如感谢你迄今为止的帮助!我还没有解决办法,但你的回答帮助我澄清了我的困惑,我
results = File.read(file, encoding: "iso-8859-1")
results.each do |line|
  puts line.split('¬')
end
Encoding::CompatibilityError: incompatible character encodings: ISO-8859-1 and UTF-8
results = File.read(file, encoding: "iso-8859-1").encode('UTF-8')
results.encoding
results = results.split("\r\n")
results.each do |line|
  puts line.split('¬')
end