convert - ruby utf 8 characters




Рубиновое преобразование строковой кодировки из ISO-8859-1 в UTF-8 не работает (2)

Я пытаюсь преобразовать строку из 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" 

Я не уверен, почему Norrlandsvägen в iso-8859-1 будет преобразован в Norrlandsvögen в utf-8.

Я пробовал кодировать, кодировать !, кодировать (destinationEncoding, originalEncoding), iconv, force_encoding и всевозможные странные обходы, о которых я мог думать, но ничего не работает. Может ли кто-нибудь помочь мне / указать мне в правильном направлении?

Рубиновый новичок все еще тянет волосы как сумасшедшие, но чувствует благодарность за все ответы здесь ... :)

Справочная информация по этому вопросу: Я пишу драгоценный камень, который загрузит XML-файл с некоторых сайтов (который будет иметь кодировку iso-8859-1) и сохранит его в хранилище, и я хотел бы сначала преобразовать его в utf-8. Но такие слова, как Норрландсваген, меня путают. На самом деле любая помощь будет принята с благодарностью!

[UPDATE]: Я понял, что выполнение тестов, подобных этому в консоли 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')

и ошибка - это Encoding::UndefinedConversionError - "\xC3" to UTF-8 in conversion from ASCII-8BIT to UTF-8 to ISO-8859-1

Я все еще довольно потерян во всем этом закодирующем беспорядке, но я очень благодарен за все ответы и помог всем мне дать! Благодаря тонну! :)


Вы назначаете строку в UTF-8. Он содержит ä . UTF-8 представляет собой два байта.

string = 'ä'
string.encoding
# => #<Encoding:UTF-8>
string.length
# 1
string.bytes
# [195, 164]

Затем вы заставляете байты интерпретироваться так, как если бы они были ISO-8859-1, без фактического изменения основного представления. Это больше не содержит. Он содержит два символа: Ã и ¤ .

string.force_encoding('iso-8859-1')
# => "\xC3\xA4"
string.length
# 2
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, как это было бы с вашего веб-сервиса - у вас есть тарабарщина. К счастью, все это в ваших консольных тестах; если вы прочтете ответ на веб-сайте, используя правильную кодировку ввода, все должно работать нормально.

Для вашего консольного теста давайте продемонстрируем, что если вы начинаете с соответствующей строки ISO-8859-1, все это работает:

string = 'Norrlandsvägen'.encode('iso-8859-1')
# => "Norrlandsv\xE4gen"
string = string.encode('utf-8')
# => "Norrlandsvägen"

EDIT Для вашей конкретной проблемы это должно работать:

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')

Существует различие между force_encoding и encode . Первый устанавливает кодировку для строки, тогда как последняя фактически перекодирует содержимое строки в новую кодировку. Следовательно, следующий код вызывает вашу проблему:

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>




iconv