Уточняю: проблема с кодировкой кириллицы.
Исходное положение:
1. Имеется комп, под управлением Linux. На компе крутится некоторое ПО (написано на С) в котором используются строки, содержащие русские слова. Кодировка UTF-8. Все работает нормально. Вопросов нет.
2. Разрабатывается некоторый девайс на микроконтроллере. В состав девайса входит символьный (не графический!) LCD индикатор. Индикатор руссифицирован, но кодировка "веселая" (пример кодировки тут http://www.gaw.ru/html.cgi/txt/lcd/chips/hd44780/start.htm -- крутите вниз).
3. Девайс предполагается использовать в качестве мини-терминала.
Я хотел бы чтобы мини-терминал сам занимался перекодировкой в свой формат. В свое время, когда я плотно сидел под Вендой, я использовал этот терминальчик для работы. Строки сообщений в Вендовых прогах я писал в кодировке CP1251. Через комповые интерфейсы я перегонял русские строки в терминал и обратно. Терминал сам занимался перекодировкой для LCD, и горя не знал -- все символы байтовые, перекодировка -- это обычная таблица. То же самое было и в отношении ДОС-овской кодировки -- CP866.
Ныне я работаю с Линухом. Тут используется кодировка UTF-8, которая имеет байтовый размер для латиницы и знаков, и двухбайтовый формат для кириллицы. Все очень неоднозначно. Получается, что софт (прошивка) терминала усложняется. Меня это несколько озадачивает, поэтому я хотел бы задать вопрос -- а я вообще правильным путем иду?
Наверняка, кто-нибудь что-нибудь подобное делал. Хотелось бы услышать ваши советы, и не ходить по граблям.
Любая критика и любые предложения приветствуются.
Проблема с кодировкой
Нужно перекодировать UTF-8 в CP1251?
zhevak!
Рил-тайм-чат с терминалом на plc oO
Но эт лирика.
А аппаратно чесать поток на соответствие каждых двух смежных байтов "русской" букве - с заменой при необходимости?
И соответственно - в обратную сторону - но уже байт на два заменять, когда необходимо.
Это - если на стороне plc (но тут и глупость могу спросить, но вдруг такое - самый дешёвый вариант - просто не силён в железАх).
Если обмен не только текстовыми сообщениями - то есть ли какие- нибудь коды для распознавания именно текста в общем потоке?
Если да - можно от них поплясать - тоже аппаратно в свете вышесказанного.
Суть - включить в канал связи электронный русификатор.
------------------------------------------------------
Если же решать в коде - то только на стороне PC -
не, ну а где ещё делать косметическое преобразование потока обмена, грузящее процессор.
Думаю, в этом случае можно не продолжать :rolleyes:
Нужно перекодировать UTF-8 в CP1251?
Не совсем.
А аппаратно чесать поток на соответствие каждых двух смежных байтов "русской" букве - с заменой при необходимости?
И соответственно - в обратную сторону - но уже байт на два заменять, когда необходимо.
Это - если на стороне plc (но тут и глупость могу спросить, но вдруг такое - самый дешёвый вариант - просто не силён в железАх).
Да, придется расчесывать поток. Причем как одну, так и в другую сторону. В сторону компа еще куда ни шло! На терминале будет либо своя клава (приблизительно только цифровая, ну плюс еще кое-какие клавиши типа Esc, Enter, стрелочки для перемещения...), либо будет подключаться стандартная комповая клава. В первом случае вообще легко. Во втором случае нужно будет тупо перегонять скан-коды клавиатуры в символы. А вот с потоком от компа в сторону терминала -- хреново. Тут не только будут присутствовать русские (двухбайтовые) и латинские (однобайтовые) символы, но еще и управляющие символы, которые будут перемещать курсор, командовать буззером, и зажигать-гасить полдюжины светодиодов. В общем-то все это можно разобрать по категориям, но уж как-то очень неожиданно возникла проблема еще и с русскими буквами.
Заниматься перекодировкой все же придется на стороне девайса, т.к. комповая прога может выводить поток как на комповую консоль (монитор, экран компа), так и перенаправлять ее в порт (USB, ttyS*).
Хех :(
zhevak, используйте терминал в KOI8-R, или CP1251. И при необходимости перекодируйте (man tr)
Да, придется расчесывать поток.
вам делать нечего? терминалы отлично работают в однобайтовой кодировке.
вам делать нечего?
простите, не понял? Вы для чего это спросили?
терминалы отлично работают в однобайтовой кодировке.
Я как раз этим и интересуюсь -- как они работают. Поэтому и создал тему. Если Вам есть что сказать, то скажите. А если нечего, то я Вас не понимаю.
zhevak!
http://www.samag.ru/cgi-bin/go.pl?q=articles;n=03.2006;a=02 - а ну как поможет:
там есть скриптик по переключению локали и консоли в CP1251
А в архиве к статье - скрыптик наоборот в UTF-8
простите, не понял? Вы для чего это спросили?
объясняю: зачем вы используете многобайтовую кодировку?
Я как раз этим и интересуюсь -- как они работают. Поэтому и создал тему. Если Вам есть что сказать, то скажите. А если нечего, то я Вас не понимаю.
ну вроде как я всё разъяснил... Что не понятно-то?
[console]$ echo "АБВГД" | LC_ALL=C sed 's/.../XYZ/'
XYZ�ВГД
[/console]
Что тут произошло?
Консоль у меня работает в UTF-8, т.е. каждый символ занимает от 1 до пяти байт. Я конечно могу вообще всё перевести в однобайтовую кодировку (как я это рекомендовал вам), но я сделал хитрее: эта команда на самом деле состоит из двух:
1) echo "АБВГД". На самом деле, эта команда получает на входе байты
0xd0, 0x90, 0xd0, 0x91, 0xd0, 0x92, 0xd0, 0x93, 0xd0, 0x94, 0x0a(в 16ой системе), и их-же выводит. В нашей кодировке это "АБВГД" (и ещё перевод строки). Так мы видим это на входе и на выходе. Почему? Потому-что:
[console]$ echo $LANG
ru_RU.UTF-8
[/console]
Впрочем, можно даже и так:
[console]$ echo "女子高生監禁凌辱 鬼畜輪姦84 一人ぼっちの転校生 - 香坂百合"
女子高生監禁凌辱 鬼畜輪姦84 一人ぼっちの転校生 - 香坂百合
[/console]
Т.е. совсем не важно, на каком языке я пишу - на любом могу. Система самостоятельно переводит байты в символы и обратно, используя специальные таблицы перевода (в которых записано, какая буква сколько занимает. Например русская А занимает 2 байта 0xd0, 0x90.).
Но ВАМ-тог этого НЕ нужно! Вам надо, что-бы каждая буква занимала РОВНО один байт. Для этого достаточно сменить системные переменные (я точно не знаю какие, их около десятка, и каждая отвечает за своё. Читайте мануалы к своему дистрибутиву для конкретики).
2) Если-бы я ограничился первой командой, то всё это преобразование было-бы скрыто, причём без разницы, сколько байт в букве и какая кодировка (за исключением китайского, который работает(на Руси) лишь в UTF-8).
Я-же воспользовался командой sed, которая поменяла три первых символа на XYZ. Однако, не всё так просто - перед командой sed написано LC_ALL=C, что привело к тому, что ВСЕ национальные особенности и кодировки ОТКЛЮЧАЮТСЯ. Фактически, становятся определёнными лишь символы 0...127, при этом каждый символ имеет размер 1 байт. Символы 128...255 не определены, как они будут выглядеть - неизвестно, но мы на 100% уверены, что их размер также 1 байт. В итоге, в строке "АБВГД" sed заменяет не первые три буквы, а первые три байта - А, и половинку Б.
Таким образом, можно переключать кодировки не только глобально в терминале, но и локально для каждой отдельно взятой команды.
Если Вам есть что сказать
а читать вы таки не желаете:
man tr
Эта команда перекодирует для вас любой хитрозапутанный набор во что угодно и обратно. На неё локали не действуют (на число символов).
Терминал сам занимался перекодировкой для LCD, и горя не знал -- все символы байтовые, перекодировка -- это обычная таблица. То же самое было и в отношении ДОС-овской кодировки -- CP866.
вот я вам команду перекодировки и дал. К ней ещё надо таблицу составить конечно. Точнее - две таблицы. Только работать надо не в юникоде.
[quote=zhevak]простите, не понял? Вы для чего это спросили?
объясняю: зачем вы используете многобайтовую кодировку?
[/quote]
я не знал, что у меня есть выбор. И до сих пор не знаю.
Я где-то читал, что в Лине кодировка UTF-8. Вроде как допускаются и другие, но общепринятая по умолчанию -- UTF-8. Вот я от нее и отталкивался. А как правильно?
[quote=zhevak]Я как раз....
ну вроде как я всё разъяснил... Что не понятно-то?
...
Таким образом, можно переключать кодировки не только глобально в терминале, но и локально для каждой отдельно взятой команды.
[/quote]
Ну вот теперь разъяснил. Вроде все встает на свои места.
Спасибо!
а читать вы таки не желаете: man tr
Эта команда перекодирует для вас любой хитрозапутанный набор во что угодно и обратно. На неё локали не действуют (на число символов).
Простите, не обратил внимания. Точнее так, не понял, что как-то это может помочь.
вот я вам команду перекодировки и дал. К ней ещё надо таблицу составить конечно. Точнее - две таблицы. Только работать надо не в юникоде.
не работать в Юникоде? Э-э... не понял. Не работать на какой строне -- на строне компа или на стороне девайсика?
Если на стороне компа, то это странно, UTF -- это же и есть Юникод
Юникод имеет несколько форм представления (англ. Unicode transformation format, UTF): UTF-8, UTF-16 (UTF-16BE, UTF-16LE) и UTF-32 (UTF-32BE, UTF-32LE). Была разработана также форма представления UTF-7 для передачи по семибитным каналам, но из-за несовместимости с ASCII она не получила распространения и не включена в стандарт. 1 апреля 2005 года были предложены две шуточные формы представления: UTF-9 и UTF-18 (RFC 4042).
В Microsoft Windows NT и основанных на ней системах Windows 2000 и Windows XP в основном используется форма UTF-16LE. В UNIX-подобных операционных системах GNU/Linux, BSD и Mac OS X принята форма UTF-8 для файлов и UTF-32 или UTF-8 для обработки символов в оперативной памяти.
http://ru.wikipedia.org/wiki/Юникод
Хорошо, а в какой кодировке тогда работать?
А если на строне коробочки-девайсика, то и сам не хочу. Почему и поднял тему. Поднял от безысходности. Хех!
Или вы что имели в виду, поясните пожалуйста.
Вопрос.
В проекте (в установке), в составе которого будет применяться девайс, поток инфы может также быть направлен на дот-маттрикс принтер. Хотелось бы единообразия. Поэтому, мне удобнее всего заложить в девайс ДОС-овскую кодировку -- CP866.
Пожалуйста, прокомментируйте такое решение.
я не знал, что у меня есть выбор. И до сих пор не знаю.
Я где-то читал, что в Лине кодировка UTF-8. Вроде как допускаются и другие, но общепринятая по умолчанию -- UTF-8. Вот я от нее и отталкивался. А как правильно?
UTF-8 - неправильно. Да, она используется в линуксах по умолчанию на десктопах и для пользователей, но - не более того. Существуют способы атаковать сервера, на которых применяется UTF-8, и потому обычно для рута она не используется.
В вашем случае нужна однобайтовая кодировка, и я не вижу причин, по которым вам её не использовать - единственное что вы потеряете - это возможность писать на нескольких языках сразу. Например вы не сможете одновременно пользоваться русским и китайским. А вам это надо? Думаю - нет.
С другой стороны, в однобайтовой кодировке есть несколько плюсов:
1) неуязвимость - регулярное выражение ".*" совпадает с любым количеством символов. Всегда. Потому его можно отфильтровать.
2) быстродействие - скрипты и программы работают в 2-3 раза быстрее только за счёт того, что не требуется вычислять длину символа. Она тождественно равна 1, а вовсе не 1...5.
3) Возможность сортировки букв - glibc умеет сортировать байты, а в нужном порядке они стоят лишь в CP1251, потому только её можно сортировать без всяких дополнительных костылей. Причём для утф костыли совсем уж костыльные :(
не работать в Юникоде? Э-э... не понял. Не работать на какой строне -- на строне компа или на стороне девайсика?
Если на стороне компа, то это странно, UTF -- это же и есть Юникод
я только про комп, паяльник уже лет 10 в руки не брал :) С девайсом своим как-нить сами ;)
Хорошо, а в какой кодировке тогда работать?
ну либо в KOI8-R (классика), либо CP1251 (вам оно будет привычнее, да вроде у вас-же есть какие-то наработки под неё? перекомпилируйте их, и используйте дальше).
Поэтому, мне удобнее всего заложить в девайс ДОС-овскую кодировку -- CP866.
ну заложите 866 - тогда и терминал пусть работает именно в этой кодировке.