Недопустимая последовательность байтов в UTF-8 Ruby

У меня есть такая строка "abce\xC3".sub("a","A"), когда я выполняю строку, я получаю следующую ошибку.

ArgumentError: invalid byte sequence in UTF-8
    from (irb):20:in `sub'
    from (irb):20
    from /home/vijay/.rvm/rubies/ruby-2.0.0-p598/bin/irb:12:in `<main>'

Может ли кто-нибудь помочь мне решить эту проблему.


person Vijay    schedule 07.07.2015    source источник
comment
Байт \xC3 не является допустимым символом UTF-8. Ваша проблема каким-то образом возникает, когда вы получаете это значение из источника (или ваши предположения о том, как можно манипулировать строками Ruby). Чтобы получить помощь, вам нужно будет немного объяснить, что это значение должно представлять или как оно было прочитано в вашей программе.   -  person Neil Slater    schedule 07.07.2015
comment
Откуда \xC3? В UTF-8 это означает, что должен следовать второй байт (например, \xA4 для ä).   -  person cremno    schedule 07.07.2015
comment
ITZVÃ это точная строка. я работаю над.   -  person Vijay    schedule 07.07.2015
comment
Похоже, что Ruby 2.2 не вызывает ошибку, т.е. sub работает с/пропускает недопустимые последовательности байтов.   -  person Stefan    schedule 07.07.2015
comment
ITZVÃ — это содержимое файла. Когда я прочитал файл . z = File.open("x"); z.read(5); Тогда вывод должен быть ITZV\xC3\x83 вместо этого я получаю ITZV\xC3. @Stefan есть идеи о том, почему это происходит в ruby.   -  person Vijay    schedule 07.07.2015
comment
@Vijay, см. мой ответ ниже.   -  person Stefan    schedule 08.07.2015


Ответы (3)


Как уже ответил Арье, эта ошибка связана с тем, что недопустимая последовательность байтов \xC3

Если вы используете Ruby 2.1+, вы также можете использовать String#scrub для замены недопустимых байтов заданным символом замены. Здесь:

a = "abce\xC3"
# => "abce\xC3" 
a.scrub
# => "abce�"
a.scrub.sub("a","A")
# => "Abce�"
person shivam    schedule 07.07.2015

Вам нужно выяснить, что вы хотите, чтобы \xC3 было. Представляет ли он символ Ã?

Вы видите ошибку, потому что \xC3 не является допустимой последовательностью байтов в кодировке UTF-8 (по умолчанию). Можно сначала исправить кодировку String (ответив на вопрос выше), а потом уже делать замену.

"abce\xC3".force_encoding("iso-8859-1").sub('a', 'A')

Или, если кодировка не имеет значения, скажем, вы обрабатываете последовательность байтов, а не последовательность символов, вы можете установить кодировку ASCII-8BIT.

"abce\xC3".force_encoding("ASCII-8BIT").sub('a', 'A')
person Arie Xiao    schedule 07.07.2015
comment
как вы нашли \xC3 это Ã ? - person Vijay; 07.07.2015
comment
А для преобразования строки в UTF-8 используйте "abce\xC3".force_encoding('iso-8859-1').encode('utf-8') или, что еще лучше, установите правильную кодировку при чтении строки. - person Stefan; 07.07.2015
comment
@Vijay Это один байт, который превышает диапазон обычной кодировки ASCII, поэтому я попробовал 8 битовое кодирование - person Arie Xiao; 07.07.2015

Что касается вашего комментария/актуальной проблемы:

"ITZVÃ" — это содержимое файла. Когда я прочитал файл .

 z = File.open("x")
 z.read(5)

Тогда вывод должен быть ITZV\xC3\x83 вместо этого я получаю ITZV\xC3

Это связано с тем, что в UTF-8 Ã является многобайтовым символом, т. е. ваша строка состоит из 5 символов, но 6 байтов:

"ITZVÃ".chars #=> ["I", "T", "Z", "V", "Ã"]
"ITZVÃ".bytes #=> [ 73,  84,  90,  86, 195, 131]

z.read(5) считывает 5 байтов из ваших файлов, возвращая таким образом неполную строку UTF-8:

require 'tempfile'

z = Tempfile.new('foo')
z << 'ITZVÃ'

z.rewind
z.read(5) #=> "ITZV\xC3"

Вместо этого вы должны прочитать 6 байтов:

z.rewind
z.read(6) #=> "ITZV\xC3\x83"

Обратите внимание, что read всегда возвращает ASCII-8BIT. закодированные строки. Вы должны установить другую кодировку вручную:

z.rewind
z.read(6).force_encoding('utf-8') #=> "ITZVÃ"
person Stefan    schedule 08.07.2015