last day (14 days later) » 

1:44 PM
0
Q: Кириллица в Ruby 1.9.2

ZEkA10000Всем привет. Впрочем у меня такая проблемка... При вводе текста (через gets.chomp) у меня выводит ошибку Есть пример: a = gets.chomp Ввожу "Привет" #=> Encoding::InvalidByteSequenceError occured "\x8F" on UTF-8 P.S. если что перед этим уже используется require 'dl' require 'zlib' require...

 
Добавьте трейс. И это происходит в irb, или просто при запуске отдельного файла с кодом тоже?
 
@D-side показать не могу, потому что используется игровой движок с таким языком (это объясняет почему я использую только v1.9.2) Немного подробностей: После ввода "Привет" в a = gets.chomp a имеет значение \x8F?\xA5\xE2 вместо Привет скриншот.
 
Хм. Непрямая отладка. Приключе-е-ения. Ладно. Попробуйте вывести gets.chomp.bytes, давайте посмотрим что он всё-таки считывает.
 
@D-side gets.chomp.bytes получил #<Enumerator:0x75031e0>
 
Ок, а теперь на нём .to_a?
 
1:44 PM
@D-side [143, 224,168, 162, 165, 226]
 
Вот мы и вышли на проблему. Кириллица ввелась по одному байту на символ. Это действительно не UTF-8.
 
@D-side однако по таблице символов Alt+ все совпадает.
 
Потому что там тоже не UTF-8.
К сожалению, у меня нет возможности быстро воспроизвести вашу ситуацию, т. к. у вас, по всей видимости, дело под Windows происходит. Но попробуйте в начале программы сделать $stdin.set_encoding('cp866') и повторите ваши опыты.
 
@D-side Не помогло
 
Точнее. Что именно произошло?
 
1:54 PM
Произошло то что написано в вопросе
Вновь ошибка в байтами \x8F и ему подобными
 
2:06 PM
Просто у вас там явно CP866.
Что в $stdin.external_encoding?
 
$stdin.external_encoding вывел utf-8
 
Это не нормально.
$stdin.set_encoding('cp866') явно не сделан.
 
Что-то не то.
Пойду 1.9.2 поставлю.
Суть проблемы: ваш входной поток выдаёт данные в CP866, а не в UTF-8, как думает руби.
 
2:22 PM
и как же сделать чтобы ввод был в UTF-8?
 
В ваших условиях очень может быть, что никак.
В каком окне происходит ввод?
 
в RGSS Console
 
Попробовал в 1.9.2, тоже работает.
Т. е. дело не в версиях, а видимо в том, что в RGSS что-то сломано.
Или чтение идёт не из того потока...
Хотя нет, сам поток не меняется.
Уже это подозрительно.
 
2:38 PM
Ну сейчас я попробовал сделать при помощи массива
 
Это уже чистой воды костылизм :D
 
Зато рабочий :D
 
Если уж браться за постобработку результатов чтения, вместо того чтобы правильно настраивать читающий поток, есть способ гораздо проще.
gets.chomp.force_encoding('cp866').encode('utf-8')
Хотя по идее, $stdin.set_encoding('cp866', 'utf-8') должен это делать со всеми вводимыми впоследствии строками автоматически.
 
gets.chomp.force_encoding('cp866').encode('utf-8') #=> unknown encoding name - cp866
 
А вот это уже интересно.
Это объясняет, почему кодировка не сменилась.
Но не объясняет, почему скрипт не упал нафиг!
Хорошо, химичим дальше.
Выведите Encoding.constants.
 
2:47 PM
Вывел
 
Эм, а где всё о_О
Для сравнения:
Хорошо, другим путём.
Encoding.list ?
 
Мда-а-а.
 
только 4
 
По ходу, надо завести отдельную метку для RGSS.
Потому что в обычном 1.9.2 кодировка CP866 имеется.
И реальный ввод не соответствует ни одной из перечисленных кодировок.
 
2:55 PM
А Encoding расширять нельзя?
 
Похоже, что нельзя, во всяком случае публичными API.
 
Однако Encoding.locale_charmap выдал CP866
 
Да, но эта кодировка в вашем руби, по всей видимости, просто не поддерживается.
Создать новую кодировку можно, только клонировав существующую (и то я не уверен, что в 1.9.2 так можно), да и даже после этого переопределить ей транскодер нельзя.
 
Хм... в 2.3.0 ситуация не лучше
 
Да ну? Намного лучше!
Он не падает :)
И он прекрасно понял, что ему на вход поступил CP866 и вывел его экранированным.
Посмотрите в a.encoding
 
3:05 PM
IBM866
 
Это она.
А теперь сделайте $stdin.set_encoding('cp866', 'utf-8') и попробуйте ещё раз.
 
в 2.3.0
 
Тоже экранирует? Забавно. Интересно, какая у него кодировка вывода. Попробуйте напечатать оба варианта.
 
В каком смысле 2 варианта?
 
В UTF-8 и в CP866.
Их можно взаимоконвертить а-ля str.encode('utf-8').
Во, таки поставил виндовый 2.4.
Опробовал сам.
Оба работают. Т. к. кодировки у обеих выставлены верно.
 
3:12 PM
в 2.3 у меня тоже что и после $stdin.set_encoding('cp866', 'utf-8')
 
Просто при инспектировании экранируется.
Похоже, что всегда.
 
Всё правильно.
 
по таблице юникода и это я понял
 
Там выводится не строка напрямую, а результат .inspect на строке. Попробуйте вывести напрямую.
 
3:15 PM
a.inspect #=> "\"\\x8F\\xA8\\xE6\\xE6\\xA0\""
 
Напрямую -> без inspect.
puts a, например.
 
так все нормально
только мне это надо решить в RGSS3 а не в cmd.exe
 
В общем, виноват RGSS, и видимо вам правда придётся колхозить самописный конвертер из CP866 в UTF-8.
К счастью, CP866 фиксированной длины, по байту.
 
Возможно...
 
У меня вышел вот такой упоротый литерал:
"\u0000\u0001\u0002\u0003\u0004\u0005\u0006\a\b\t\n\v\f\r\u000E\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A\e\u001C\u001D\u001E\u001F !\"\#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007FАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмноп░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀рстуфхцчшщъыьэюяЁёЄєЇїЎў°∙·√№¤■ "
 
3:20 PM
ну по таблице символов я заметил что идет отсчет с 21 элемена в UTF-8
 
Эту строку, в теории, можно эксплуатировать вот так: input.bytes.map(&cp866.method(:[])).join (где cp866 это строка сверху)
Это может выглядеть немного дико, вот чуть более понятная версия: input.bytes.map { |byte| cp866[byte] }.join
Надо только проследить, что строка cp866 в кодировке UTF-8.
 
`undefined local variable or method 'input' for main:Object`
`undefined local variable or method 'cp866' for main:Object`
 
Ну ясен пень, их определить надо.
input это входная строка, а про cp866 я даже отдельно написал.
 
и как же cp866 мне нормально определить?
 
cp866 =
7 mins ago, by D-side
"\u0000\u0001\u0002\u0003\u0004\u0005\u0006\a\b\t\n\v\f\r\u000E\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A\e\u001C\u001D\u001E\u001F !\"\#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007FАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмноп░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀рстуфхцчшщъыьэюяЁёЄєЇїЎў°∙·√№¤■ "
Например.
Безопасности ради символы, которые вам точно не потребуются, можно заменить на что-то менее опасное, например _, но лучше оставить как есть.
Чтоб не оставлять лишних переменных вроде кодировки исходного кода.
Хочется верить, что хотя бы он в UTF-8.
 
3:31 PM
все так же x8F подобные
 
p тоже выводит с инспектом.
Но вообще да, это может быть проблемой.
 
вот я только через p и могу вывести без InvalidByteSequence
 
А точнее?
Вообще, судя по выводу, он неправильно составил строку.
 
Что там точнее? '\x8F' to UTF-8
 
В UTF-8. Хм.
Что в cp866.encoding?
 
3:36 PM
cp866.encoding #=> "UTF-8"
 
Очень интересно.
А что в cp866.bytes.first(5) ?
 
cp866.bytes.first(5) #=> [0, 1, 2, 3, 4]
 
Ок, теперь надо посмотреть на многобайтовые символы, момент
cp866[160..170].bytes.length
Должно быть 22.
Т. к. там 11 кириллических букв в UTF-8.
Хотя это можно было распознать и проще, по cp866.bytes.length (должно быть 436)
 
undefined method 'length' for #<Enumerator: "абвгдежзийк":bytes>
 
Аргх, 1.9.2 же. Ну, как обычно, .bytes.to_a.
 
3:43 PM
cp866[160..170].bytes.length
cp866[160..170].bytes.to_a.length #=> 22
 
Хм. Это правильно.
Тогда непонятно, каким это образом в p a получаются однобайтовые символы, в какой момент они преобразуются.
Если в cp866 они исходно двухбайтовые.
 
А, момент. Скорее всего это делает p.
Что в той преобразованной "пицце" в байтах?
 
снять комментарий и заного?
или как?
 
Да, наверное так.
А, стоп
Хе-хе-хе
Так вы ничего не преобразовали.
Точнее, преобразовали, а результат преобразования выкинули.
18 mins ago, by ZEkA10000
user image
В 3 строке выражение вычисляется, а его результат выкидывается. Вы его присвойте куда-нибудь и дальше пользуйтесь им.
 
3:51 PM
Получилось
 
То есть, чистый UTF-8 он всё-таки выводит?
Это хорошая новость.
 
но мне тогда придется cp866 сделать глобальной и использовать input.bytes.map { |byte| $cp866[byte] }.join
 
Сделайте класс, вкрутите cp866 туда константой, выставьте преобразование в форме метода у этого класса.
 
вот константы я еще не изучил
и как к ним обращаться тоже
 
Причесал вопрос, посмотрите, ничего ли не потерял.
 
4:01 PM
Спасибо, выручили :)
 

last day (14 days later) »