|
|
Корректная обработка кодировок с буквой ЁД.В. Хмелёв18 марта 2002
Содержание1 Введение2 Перекодировка вручную 2.1 Декодирование с помощью браузеров (IE, Netscape) 2.2 Импорт и экспорт кодовой страницы 866 в Word 2.3 Внутри файлового менеджера Far 2.4 Внутри редактора (X)Emacs (пакет russian.el) 3 Перекодировка с помощью внешней программы xcode.c 4 Перекодировка внутри программы (библиотека SRECODE) 4.1 На языке Perl 4.2 На языке Си 5 О перестановочной кодировке и iconv 6 Таблицы кодировок
1 ВведениеНесмотря на то, что существует великое множество программ преобразования текстов из одной кодировки в другую, подавляющее большинство из них (по-видимому, единственное исключение представляют программы, приведённые на этой странице!) страдают общим дефектом: потерей информации при перекодировке. Здесь показано, что перекодировка текста возможна без потери информации и приведены программа для такой перекодировки и функции на языках программирования Си и Перл, обеспечивающие обратимую перекодировку текстов на русском языке.Русская Кодировка - это набор чисел, используемых внутри компьютера для обозначения 66 русских букв (33-х больших и 33-х маленьких). Более точно, каждой букве Я соответствует её номер (код) n(Я) и наоборот. Такой набор кратко называют кодировкой. На самом деле, числовое представление имеют и другие символы: знаки препинания, пробел, цифры, латинский алфавит и т.д. Исторически этот алфавит на компьютерах закрепился в качестве стандарта, так называемого, ASCII. Символы в стандарте ASCII имеют коды от 0 до 127=27-1, и требуют для своего представления 7 битов. Единицей хранения информации на компьютере, однако, является байт, то есть 8 битов. Это привело к тому, что коды русских букв в распространённых кодировках принимают значения от 128=27 до 255=28-1. Под перекодировкой мы будем понимать преобразование текста T в кодировке n в текст Tў тем же содержанием в кодировке m. К сожалению, обычно используется подстановочная перекодировка T® Tў. Именно, каждая русская буква Я текста T с кодом n(Я) переводится в букву с кодом m(Я). Потенциально (и реально!) это приводит к потере информации. Действительно, если в тексте T присутствовал какой-то дополнительный символ из расширения русской кодировки (например, символ текстовой графики) с кодом m(Я), то этот символ перемешается с преобразованной буквой n(Я) и возникнет «графика из букв». Поэтому при обратном преобразовании «буквенная графика» сохранится и данный символ псевдографики безнадёжно перемешается с буквами. Более того, это приводит к потере информации при неправильной перекодировке текста (например, текст был в кодировке cp1251, а его ошибочно преобразовали конвертером koi®cp866). Но можно ли избежать потери информации? Такой способ есть. Надо использовать ПЕРЕСТАНОВОЧНУЮ перекодировку. Именно, вместо подстановки надо использовать перестановку. Действительно, вообразим, что русская кодировка состоит не из 66 букв, а из 128. Между двумя кодировками n(·) и m(·) существует взаимно-однозначное соответствие по подмножеству из 66 букв алфавита. Установим какое-нибудь взаимно-однозначное соответствие на оставшихся 128-66=62 кодах. Тогда при перекодировке не будет происходить никакой потери информации. Даже если к тексту применена неправильная перекодировка, его всегда можно восстановить, проделав обратную операцию. Пример, поясняющий перестановочную кодировку, приведён в разделе 5. А теперь, пожалуйста, задумайтесь: ни один из распространённых перекодировщиков не является перестановочным. Между тем, если бы все перекодирующие программы придерживались этого соглашения, то уж во всяком случае была бы возможна универсальная программа, восстанавливающая кодировку утраченного русского текста. В разделе 4 приведены функции на языках Перл и Си, которые обеспечивают перестановочную перекодировку. Кстати говоря, перестановочная перекодировка полезна и с точки зрения программирования: действительно, можно перестановочной перекодировкой преобразовать входные данные, скажем, в кодировку sort (см. раздел 6) в которой коды букв (включая нашу несчастную букву Ё) располагаются в алфавитном порядке и таким образом легко применять программы сортировки (разумеется, в предположении, что не задействована локаль - но где она задействована, и поддерживает ли она букву Ё?). Существует большое количество программ, которые автоматически определяют кодировку текста и преобразуют её в желаемую. Такие программы удобны для применения в пакетном режиме. Однако, надо свято верить в то, что кодировка определится правильно, поскольку иначе подстановочный перекодировщик может перекодировать текст неправильно - и информация безвозвратно испортится. В разделе 3 описан перестановочный перекодировщик с автоматическим определением кодировки. Такой перекодировщик можно без опаски применять на практике: в подавляющем большинстве случаев он будет давать правильный результат, а в редких исключительных случаях неправильного определения кодировки всегда можно восстановить зашифрованную информацию.
Перекодировку иногда удобно осуществлять вручную, то есть, набрав последовательность команд в какой-нибудь оболочке, позволяющей проводить перекодировку. Иногда (в частности, при пакетной обработке файлов) перекодировку удобно осуществлять с помощью вызова внешних программ. Третий случай, когда может потребоваться перекодировка - это перекодировка внутри программы, когда необходим некоторый программный код, обрабатывающий данные. Все эти способы рассмотрены в следующих разделах. В разделе 2 описано, как можно перекодировать тексты из одной кодировки в другую вручную в широко распространённых программных средствах. Отметим, что все эти способы обеспечивают лишь сохранение букв русского алфавита, то есть эти перекодировки не являются перестановочными. Разделы 3 и 4 посвящены реализации перестановочной перекодировки. Автор признателен Андрею Бирюку за подсказанную идею перестановочной перекодировки. Автор также признателен Сергею Скотникову за конструктивное замечание.
2 Перекодировка вручнуюЗаранее просим прощения у читателя, который сочтёт нижеприведённые советы очевидными. Напротив, настоящий текст задумывался как всем понятный справочник по перекодировке. Поэтому, если вам что неясно - не обвиняйте себя в непонятливости, напишите по адресу, приведённому в конце страницы.Разумеется, здесь упомянуты не все возможные способы. Мы концентрируемся в первую очередь на тех способах, которые проверены на сохранение буквы Ё при перекодировке. Если кто-то обладает замечательной программой перекодировки, которая поддерживает букву Ё, но здесь не упомянута, то немедленно сообщите об этом по адресу, приведённому в конце страницы.
2.1 Декодирование с помощью браузеров (IE, Netscape)В большинстве систем можно попытаться запустить браузер и открыть в нём через следующее меню искомый файл с неясной кодировкой.
Замечания. В большинстве систем под Unix-подобными машинами все русские шрифты установлены. На современных серверах Sun при входе в систему даже можно выбрать русский язык в качестве альтернативного (меню Options/Languages). Недостатки. Разумеется, вы сможете таким образом прочитать другой файл, но не сможете перекодировать ваш файл в кодировку отличную от принятой в системе. Например, на упоминавшихся Sun-машинах в качестве основной принята кодировка ISO-8859-5 и ваш реципиент скорее всего файл в такой кодировке не поймёт. Кроме того, возможен перехлёст бедной буковки Ё с другими локальными буквами: например, Ё в кодировке КОИ-8 имеет код, соответствующий знаку английского фунта в Великобритании. Таким образом, при стандартных системных шрифтах в Англии можно и не увидеть буквы Ё, поскольку фунт у англичан превалирует над всем остальным...
2.2 Импорт и экспорт кодовой страницы 866 в WordВ русифицированной программе Word можно импортировать обычный текстовый файл в кодировке Alt под названием «Текст DOS». В меню «Сохранить как...» можно выбрать тип файла «Текст DOS» и он сохранится по-прежнему в кодировке Alt. Импорт и экспорт файлов типа «Текст» подразумевает, что они находятся в кодировке win-cp1251.
2.3 Внутри файлового менеджера FarФайловый менеджер Far доступный по адресу http://www.rarlab.com и бесплатный для пользователей из xUSSR - читайте
Чтобы перекодировать файл (или его фрагмент) из одной кодировки в другую, необходимо выполнить следующие действия:
Заметим также, что в оболочке Far возможно автоматическое определение кодировки при открытии файла для просмотра или редактирования. Необходимую опцию необходимо проставить в опциях редактора и программы просмотра.
2.4 Внутри редактора (X)Emacs (пакет russian.el)Напомним, что в редакторе (X)Emacs (см. раздел Поддержка) под комбинацией M- < буква > подразумевается обычно комбинация клавиш < Alt > + < буква > . На клавиатурах в Sun-системах роль M исполняет клавиша Meta слева от пробела с изображённым на ней ромбиком. Если ни Alt ни Meta нет, то можно комбинацию M- < буква > набирать последовательным нажатием клавиш < Esc > и < буква >При правильно настроенном пакете russian.el (см. также внешнюю ссылку) перекодировка осуществляется набором
Чтобы отобразить файл в нужной кодировке необходимо набрать
Пакет russian.el способен также определять автоматически тип кодировки. Для этого необходимо выполнить команду
3 Перекодировка с помощью внешней программы xcode.cСледующая чрезвычайно простая в использовании программа xcode.c автоматически и весьма надёжно определяет одну из четырёх возможных кодировок файла и перекодирует его в нужную кодировку. Её удобно использовать в пакетном режиме, чтобы, например, автоматически приводить все файлы в директории к единой кодировке. Программа xcode вызывается из командой строки и по умолчанию пытается читать стандартный ввод. Помощь по программе выводится при набореxcode -hЗаметим, что при желании можно подавить определение кодировки и задать исходную и нужную кодировку с помощью соответствующих ключей. Эта программа проверена на сохранение русского алфавита при всех возможных его преобразованиях между кодировками и очень рекомендуется к использованию. Подробное описание этой программы можно найти в разделе xcode. Замечательной особенностью xcode является обратимость перекодировки. В отличие от всех остальных программ перекодировки, программа xcode перекодирует файлы без потери информации. Именно, вместо того, чтобы просто подставлять вместо одних русских букв другие, программа xcode осуществляет перестановку букв, что приводит к тому, что никакой информации не теряется вообще. Разумеется, с её же помощью можно осуществить обратную перестановку, указав обратные кодировки. Таким образом можно восстановить даже ошибочно перекодированный двоичный файл! Более того, даже если вы не помните какие кодировки были применены программой xcode, информацию из файла можно восстановить ручным подбором обратной кодировки, с использованием, например, частотного анализа. Это обуславливает безопасность применения программы xcode при пакетной обработке данных. Например, при пакетной перекодировке всех файлов в поддиректории. Исходный текст ./src/xcodesrc.zip Программа доступна под следующие операционные системы: DOS ./bin/xcodedos.zip Рекомендуется скопировать программу в одну из директорий, находящихся в переменной окружения PATH. Win ./bin/xcodewin.zip Рекомендуется скопировать программу в %WINDOWS%\COMMAND (что часто совпадает с C:\WINDOWS\COMMAND). Эта версия отличается от версии для DOS и скомпилирована как консольное приложение win32. Unix ./bin/linux.zip Для glibc версии >1.2. Должна работать под всеми современные дистрибутивами Линукса (программа была откомпилирована под SuSE 8.1) ./bin/xcoderedhat71.zip для RedHat 7.1 (больше не поддерживается) ./bin/xcodesun.zip для Sun Solaris 8 (больше не поддерживается). Обратите внимание, что xcode.c распространяется на условиях Ё-ware. То есть, программу xcode.c можно свободно распространять, модифицировать, и даже дизассемблировать как в двоичном виде, так и в исходном тексте. Однако, используя эту программу, вы должны использовать букву Ё во всех текстах, которые набираете на компьютерах: начиная с электронных писем и заканчивая крупной прозаической формой. При компиляции программы xcode.c определите параметр D_KOI (D_ALT), определяющий вывод на экран в кодировке koi8-r (cp866 выводим). Например так: gcc xcode.c -DD_KOI -O3 -o xcode
4 Перекодировка внутри программы (библиотека SRECODE)Отметим, что данные, приведённые ниже, сгенерированы автоматически с помощью скрипта russian.pl, который любознательный читатель может немедленно загрузить, а может и просто удовлетвориться тем, что написано далее... Предлагаемые подпрограммы перекодировки являются обратимыми, что позволяет, например, использовать введённую кодировку sort для сортировки строк по алфавиту с учётом правильного порядка буквы Ё. Именно, можно перекодировать имеющиеся данные в кодировку sort и затем просто сортировать их. Мы не предлагаем использовать кодировку sort для хранения данных на внешних носителях, но она вполне годится для внутренней кодировки данных в программе. Ещё раз подчеркнём, что принципиальное отличие предлагаемых процедур перекодировки состоит в том, что они перестановочные в отличие от используемых обычно подстановочных перекодировок.Набор подпрограмм с данными о кодировках составляет небольшую, но полезную библиотеку, которую решено назвать SRECODE.PL в Перл-варианте и SRECODE.C в Си-варианте. Название SRECODE следует расшифровывать как Shuffle RECODE (перестановочная перекодировка).
4.1 На языке PerlДалее приведён исходный текст подпрограммы на языке Перл, которая позволяет перекодировать любую из приведённых в разделе 6 кодировок русских букв в любую другую перестановочной перекодировкой. Все перекодировки тестируются с помощью повторного перекодирования строки из букв алфавита в кодировке КОИ-8 в две других кодировки с возвратом в исходную. Можно скопировать текст программы прямо отсюда в буфер обмена (учтите только, что некоторые браузеры не умеют слишком много информации в буфер копировать), а можно и просто загрузить её: srecode.pl.Паша Петриенко заметил, что если вы пытаетесь использовать системные программы сортировки, то можете столкнуться с живой локалью, которая под тем или иным видом существует нынче везде. Поэтому если есть желание открыть отсортированный файл в кодировке sort, надо писать что-то вроде
open(IN, "LANG= LC_ALL= sort +2 tmp.txt |") --- это для FreeBSD open(IN, "LANG= LC_COLLATE= sort +2 tmp.txt |") --- это для Linux Кроме того, помните, что перекодировка в koi7 - это вовсе не транслитерация! Легко заметить, что при перекодировке koi8-r®koi7 латинские буквы переходят в невесть что. Это не ошибка, а особенность: иначе перекодировка не будет обратимой.
#!/usr/bin/perl # Библиотека SRECODE.PL (Shuffle RECODE) вер. 1.0 # Library SRECODE.PL (Shuffle RECODE) ver. 1.0 # Автор кода: Д.В.Хмелёв, Март 2002--апрель 2003 # Подробности: http://www.rusf.ru/books/yo # Подпрограммы на языке Перл, обеспечивающие # перестановочную перекодировку 14 кодировок # русских букв друг в друга. # Functions for Perl, providing exchange # transformation of 14 russian encodings to # each other. # Следующий код является Ё-ware, Именно, его можно # свободно распространять модифицировать, и даже # дизассемблировать как в двоичном виде, так и в # исходном тексте. Однако, используя этот код, вы # должны использовать букву Ё во всех текстах, # которые набираете на компьютерах: начиная с # электронных писем и заканчивая крупной # прозаической формой. # Автор воздерживается от всяческих гарантий # надёжности кода и снимает с себя ответственность # за возможную потерю данных при его # использовании. Тем не менее, автор постарался # сделать всё возможное, чтобы потери данных можно # было избежать. # Written by D.V. Khmelev, March 2002 -- April 2003 # More information at http://www.rusf.ru/books/yo # The following code is YO-ware. YO-ware means that # you can freely copy, modify and disassemble it in # binary and/or source text. However, if you use # this program code, you should use Russian letter # YO in all texts in Russian you type in computer # from e-mails to novels. # The author disclaims any responsibility for code # safety and holds no responsibility for the loss of # data, resulting the the use of the following # code. However, the author tried to do his best to # avoid loss of data. %CODE_TABLE=( "cp866" => "\240-\245\361\246-\257\340-\357\200-\205". "\360\206-\237\0-\177\260-\337\362-\377", "cp1251" => "\340-\345\270\346-\377\300-\305\250". "\306-\337\0-\247\251-\267\271-\277", "koi8-r" => "\301\302\327\307\304\305\243". "\326\332\311-\320\322-\325\306". "\310\303\336\333\335". "\337\331\330\334\300". "\321\341\342\367\347\344\345". "\263\366\372\351-\360\362-\365". "\346\350\343\376\373". "\375\377\371\370\374". "\340\361\0-\242\244-\262\264-\277", "iso8859-5" => "\320-\325\361\326-\357\260-\265\241". "\266-\317\0-\240\242-\257\360\362-\377", "mac" => "\340-\345\336\346-\376\337\200-\205". "\335\206-\237\0-\177\240-\334\377", "osn" => "\320-\325\361\326-\357\260-\265\360". "\266-\317\0-\257\362-\377", "moshkov" => "\341\342\367\347\344\345\243". "\366\372\351-\360\362-\365\346". "\350\343\376\373\375". "\256\371\370\374\340". "\361\301\302\327\307\304\305". "\263\326\332\311-\320\322-\325". "\306\310\303\336\333". "\335\254\331\330\334". "\300\321\0-\242\244-\253\255". "\257-\262\264-\277\337\377", "sort" => "\241-\301\200-\240\0-\177\302-\377", "alt-fido" => "\240-\245\361\246-\257\160\341-\357". "\200-\205\360\206-\214\110\216-\237". "\0-\107\111-\157\161-\177\215\260-\340". "\362-\377", "koi7" => "\101\102\127\107\104\105\43". "\126\132\111-\120\122-\125\106". "\110\103\136\133\135". "\137\131\130\134\134\100". "\121\141\142\167\147\144\145". "\44\166\172\151-\160\162-\165". "\146\150\143\176\173". "\175\42\171\170\174". "\140\161\0-\41\45-\77\177-\377", "dkoi" => "\167\170\257\215\212\213\131". "\256\262\217\220\232-\237\252-\255". "\214\216\200\266\263". "\265\267\261\260\264". "\166\240\271\272\355\277". "\274\275\102\354\372\313-\317". "\332-\334\336\337\352\353\276\312". "\273\376\373\375\165". "\357\356\374\270\335". "\0-\101\103-\130\132-\164\171-\177\201-\211". "\221-\231\241-\251\300-\311\320-\331\340-\351". "\360-\371\377", "cp500" => "\254\151\355\356\353\357". "\111\354\277\200\375\376". "\373\374\255\256\131\104\105\102". "\106\103\107\234\110". "\124\121-\123\130\125-\127\220". "\217\352\372\276\240". "\252\266\263\235\332". "\233\213\267-\271\253\144\145". "\142\146\143\147\236". "\150\164\161-\163\170\165-\167". "\0-\101\112-\120\132-\141\152-\160\171-\177". "\201-\212\214-\216\221-\232\237\241-\251". "\257-\262\264\265\272-\275\300-\331\333-\351". "\360-\371\377", "ebcdic" => "\237\240\252-\255\335\256-\277\312-\317". "\332\333\130\131\142-\145\102\146-\151". "\160-\170\200\212-\220\232-\236\0-\101". "\103-\127\132-\141\152-\157\171-\177\201-\211". "\221-\231\241-\251\300-\311\320-\331\334". "\336-\377", "ascii" => "\141\142\167\147\144\145\136". "\166\172\151-\160\162-\165\146". "\150\143\75\133\135". "\43\171\170\134\134\140". "\161\101\102\127\107\104\105". "\46\126\132\111-\120\122-\125". "\106\110\103\53\173". "\175\44\131\130\174". "\176\121\0-\42\45\47-\52". "\54-\74\76-\100\137\177-\377", ); ############################################# # Перекодировать текст и вернуть результат. # использует теблицу %CODE_TABLE, # определённую выше. Пример использования: # Ex: $str=recode_var($str, $from, $to); # # Recode text and return its content. # Uses %CODE_TABLE defined above. # Ex: $str=recode_var($str, $from, $to); ############################################# sub recode_var { my ($text, $from, $to) = @_; if (!$from){ die"Recode error: Source encoding is not set."; } if (!$CODE_TABLE{$from}){ die "Recode error: Undefined source code set ($from)."; } if (!$to){ die"Recode error: Destination encoding is not set."; } if (!$CODE_TABLE{$to}){ die"Recode error: Undefined destination code set ($to)."; } $_ = $text; eval "tr/$CODE_TABLE{$from}/$CODE_TABLE{$to}/"; return $_; } sub testencs{ my $teststr= #all letters in KOI-8 encoding "\301\302\327\307\304\305\243\326\332". "\311\312\313\314\315\316\317\320". "\322\323\324\325\306\310\303\336". "\333\335\337\331\330\334\300\321". "\341\342\367\347\344\345\263\366\372". "\351\352\353\354\355\356\357\360". "\362\363\364\365\346\350\343\376". "\373\375\377\371\370\374\340\361"; my ($to1,$to2); foreach $to1(keys %CODE_TABLE){ my $res1=recode_var($teststr,"koi8-r",$to1); foreach $to2(keys %CODE_TABLE){ my $res2=recode_var($res1,$to1,$to2); if(!(recode_var($res2,$to2,"koi8-r") eq $teststr)){ die "Unsuccesful recoding: koi8-r->$to1->$to2->koi8-r"; } } } print "No information losses for all the encodings!\n"; } testencs();
4.2 На языке СиЯзык Си является нынешним lingva franca в программировании. Мы приведём таблицы кодировок с корректно поставленной буквой Ё для языка Си, функцию fill_recode_table, которая строит таблицу перекодировки и ещё пары функций srecode и srecode2, которая перекодирует заданные строки в нужные кодировки.Кодировки хранятся в строках, которые содержат последовательность кодов, отвечающих сначала тридцати трём строчным буквам, а затем тридцати трём прописным буквам: char *alphabet="абвгдеёжзийклмнопрстуфхцчшщъыьэюя" "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ";Опять-таки, можно скопировать фрагмент программы прямо отсюда в буфер обмена, а можно и загрузить её: srecode.c.
/* Библиотека SRECODE.C (Shuffle RECODE) вер. 1.0 * Library SRECODE.C (Shuffle RECODE) ver. 1.0 * Автор кода: Д.В.Хмелёв, Март 2002--апрель 2003 * Подробности: http://www.rusf.ru/books/yo * Подпрограммы на языке Си, обеспечивающие * перестановочную перекодировку 14 кодировок * русских букв друг в друга. * Functions for Perl, providing exchange * transformation of 14 russian encodings to * each other. * Следующий код является Ё-ware, Именно, его можно * свободно распространять модифицировать, и даже * дизассемблировать как в двоичном виде, так и в * исходном тексте. Однако, используя этот код, вы * должны использовать букву Ё во всех текстах, * которые набираете на компьютерах: начиная с * электронных писем и заканчивая крупной * прозаической формой. * Автор воздерживается от всяческих гарантий * надёжности кода и снимает с себя ответственность * за возможную потерю данных при его * использовании. Тем не менее, автор постарался * сделать всё возможное, чтобы потери данных можно * было избежать. * Written by D.V. Khmelev, March 2002 -- April 2003 * More information at http://www.rusf.ru/books/yo * The following code is YO-ware. YO-ware means that * you can freely copy, modify and disassemble it in * binary and/or source text. However, if you use * this program code, you should use Russian letter * YO in all texts in Russian you type in computer * from e-mails to novels. * The author disclaims any responsibility for code * safety and holds no responsibility for the loss of * data, resulting the the use of the following * code. However, the author tried to do his best to * avoid loss of data. */ typedef enum { CP866=0, CP1251, KOI8_R, ISO8859_5, MAC, OSN, MOSHKOV, SORT, ALT_FIDO, KOI7, DKOI, CP500, EBCDIC, ASCII, TOTAL_ENCODING_NUMBER} encoding_t; char * encoding_name[]={ "cp866", /* CP866 */ "cp1251", /* CP1251 */ "koi8-r", /* KOI8_R */ "iso8859-5", /* ISO8859_5 */ "mac", /* MAC */ "osn", /* OSN */ "moshkov", /* MOSHKOV */ "sort", /* SORT */ "alt-fido", /* ALT_FIDO */ "koi7", /* KOI7 */ "dkoi", /* DKOI */ "cp500", /* CP500 */ "ebcdic", /* EBCDIC */ "ascii", /* ASCII */ }; unsigned char * encoding_alphabet[]={ /* CP866 */ (unsigned char*) "\240\241\242\243\244\245\361\246\247\250" "\251\252\253\254\255\256\257\340\341\342" "\343\344\345\346\347\350\351\352\353\354" "\355\356\357" "\200\201\202\203\204\205\360\206\207\210" "\211\212\213\214\215\216\217\220\221\222" "\223\224\225\226\227\230\231\232\233\234" "\235\236\237", /* CP1251 */ (unsigned char*) "\340\341\342\343\344\345\270\346\347\350" "\351\352\353\354\355\356\357\360\361\362" "\363\364\365\366\367\370\371\372\373\374" "\375\376\377" "\300\301\302\303\304\305\250\306\307\310" "\311\312\313\314\315\316\317\320\321\322" "\323\324\325\326\327\330\331\332\333\334" "\335\336\337", /* KOI8_R */ (unsigned char*) "\301\302\327\307\304\305\243\326\332\311" "\312\313\314\315\316\317\320\322\323\324" "\325\306\310\303\336\333\335\337\331\330" "\334\300\321" "\341\342\367\347\344\345\263\366\372\351" "\352\353\354\355\356\357\360\362\363\364" "\365\346\350\343\376\373\375\377\371\370" "\374\340\361", /* ISO8859_5 */ (unsigned char*) "\320\321\322\323\324\325\361\326\327\330" "\331\332\333\334\335\336\337\340\341\342" "\343\344\345\346\347\350\351\352\353\354" "\355\356\357" "\260\261\262\263\264\265\241\266\267\270" "\271\272\273\274\275\276\277\300\301\302" "\303\304\305\306\307\310\311\312\313\314" "\315\316\317", /* MAC */ (unsigned char*) "\340\341\342\343\344\345\336\346\347\350" "\351\352\353\354\355\356\357\360\361\362" "\363\364\365\366\367\370\371\372\373\374" "\375\376\337" "\200\201\202\203\204\205\335\206\207\210" "\211\212\213\214\215\216\217\220\221\222" "\223\224\225\226\227\230\231\232\233\234" "\235\236\237", /* OSN */ (unsigned char*) "\320\321\322\323\324\325\361\326\327\330" "\331\332\333\334\335\336\337\340\341\342" "\343\344\345\346\347\350\351\352\353\354" "\355\356\357" "\260\261\262\263\264\265\360\266\267\270" "\271\272\273\274\275\276\277\300\301\302" "\303\304\305\306\307\310\311\312\313\314" "\315\316\317", /* MOSHKOV */ (unsigned char*) "\341\342\367\347\344\345\243\366\372\351" "\352\353\354\355\356\357\360\362\363\364" "\365\346\350\343\376\373\375\256\371\370" "\374\340\361" "\301\302\327\307\304\305\263\326\332\311" "\312\313\314\315\316\317\320\322\323\324" "\325\306\310\303\336\333\335\254\331\330" "\334\300\321", /* SORT */ (unsigned char*) "\241\242\243\244\245\246\247\250\251\252" "\253\254\255\256\257\260\261\262\263\264" "\265\266\267\270\271\272\273\274\275\276" "\277\300\301" "\200\201\202\203\204\205\206\207\210\211" "\212\213\214\215\216\217\220\221\222\223" "\224\225\226\227\230\231\232\233\234\235" "\236\237\240", /* ALT_FIDO */ (unsigned char*) "\240\241\242\243\244\245\361\246\247\250" "\251\252\253\254\255\256\257\160\341\342" "\343\344\345\346\347\350\351\352\353\354" "\355\356\357" "\200\201\202\203\204\205\360\206\207\210" "\211\212\213\214\110\216\217\220\221\222" "\223\224\225\226\227\230\231\232\233\234" "\235\236\237", /* KOI7 */ (unsigned char*) "\101\102\127\107\104\105\43\126\132\111" "\112\113\114\115\116\117\120\122\123\124" "\125\106\110\103\136\133\135\137\131\130" "\134\100\121" "\141\142\167\147\144\145\44\166\172\151" "\152\153\154\155\156\157\160\162\163\164" "\165\146\150\143\176\173\175\42\171\170" "\174\140\161", /* DKOI */ (unsigned char*) "\167\170\257\215\212\213\131\256\262\217" "\220\232\233\234\235\236\237\252\253\254" "\255\214\216\200\266\263\265\267\261\260" "\264\166\240" "\271\272\355\277\274\275\102\354\372\313" "\314\315\316\317\332\333\334\336\337\352" "\353\276\312\273\376\373\375\165\357\356" "\374\270\335", /* CP500 */ (unsigned char*) "\254\151\355\356\353\357\111\354\277\200" "\375\376\373\374\255\256\131\104\105\102" "\106\103\107\234\110\124\121\122\123\130" "\125\126\127" "\220\217\352\372\276\240\252\266\263\235" "\332\233\213\267\270\271\253\144\145\142" "\146\143\147\236\150\164\161\162\163\170" "\165\166\167", /* EBCDIC */ (unsigned char*) "\237\240\252\253\254\255\335\256\257\260" "\261\262\263\264\265\266\267\270\271\272" "\273\274\275\276\277\312\313\314\315\316" "\317\332\333" "\130\131\142\143\144\145\102\146\147\150" "\151\160\161\162\163\164\165\166\167\170" "\200\212\213\214\215\216\217\220\232\233" "\234\235\236", /* ASCII */ (unsigned char*) "\141\142\167\147\144\145\136\166\172\151" "\152\153\154\155\156\157\160\162\163\164" "\165\146\150\143\75\133\135\43\171\170" "\134\140\161" "\101\102\127\107\104\105\46\126\132\111" "\112\113\114\115\116\117\120\122\123\124" "\125\106\110\103\53\173\175\44\131\130" "\174\176\121", }; int *full_encoding_list(encoding_t encoding, int table[]){ int i,j; static int exists[256]; for(i=0;i<256;i++) exists[i]=0; for(i=0;i<66;i++) { table[i]=encoding_alphabet[encoding][i]; exists[table[i]]=1; } for(j=66,i=0;i<256;i++){ if(exists[i]) continue; table[j++]=i; } return table; } int *fill_recode_table(int table[], encoding_t from, encoding_t to){ static int full_enc_from[256]; static int full_enc_to[256]; int i; full_encoding_list(from,full_enc_from); full_encoding_list(to,full_enc_to); for(i=0;i<256;i++) table[full_enc_from[i]]=full_enc_to[i]; return table; } unsigned char *srecode(unsigned char *s, encoding_t from, encoding_t to){ static int prev_from=-1, prev_to=-1; static int recode_table[256]; int i; if((from!=prev_from)||(to!=prev_to)){ prev_from=from; prev_to=to; fill_recode_table(recode_table,from,to); } for(i=0;s[i];i++) s[i]=recode_table[s[i]]; return s; } unsigned char *srecode2(unsigned char *s, unsigned char *t, encoding_t from, encoding_t to){ static int prev_from=-1, prev_to=-1; static int recode_table[256]; int i; if((from!=prev_from)||(to!=prev_to)){ prev_from=from; prev_to=to; fill_recode_table(recode_table,from,to); } for(i=0;t[i];i++) s[i]=recode_table[t[i]]; s[i]=0; return s; } /* конец кода библиотеки SRECODE.C * * end of the code of the library SRECODE.C */
5 О перестановочной кодировке и iconvВопрос Я не очень понял суть перестановочной перекодировки. Протестировав xcode на нескольких файлах я заметил, что файлы перекодированные xcode и iconv ничем не отличаются (файлы сравнивались при помощи kompare) если в тексте нет псевдографики. На псевдографике iconv сбивается, а xcode оставляет в этих местах крякозябры. Как я понял, перестановочная перекодировка заменяет только русские буквы, а все остальные коды оставляет как есть. Правильно? Это единственное отличие от других перекодировщиков? Наоборот. Все подстановочные перекодировщики заменяют только русские буквы, а перестановочная кодировка заменяет все буквы. Попробую объяснить на следующем примере. Пусть вместо 128 кодов в верхней половине кодовой таблицы имеется всего 5 кодов, а буквы занимают на 66 кодов, а 3. И пусть будет две кодировки этих трёх букв:
То есть, в первой кодировке код А - 1, а во второй код А - 2 и т.д. Обычный перекодировщик из первой кодировки во вторую коду 1 сопоставляет код 2, коду 2 коду 4, коду 3, код 5. Коды 4 и 5 остаются на месте. Итого
Очевидно, буквы с коды 2 и 4 отображаются в один код - 4. Таким образом, если на входе был бинарный файл (содержащий не только символы алфавита, а например, ещё и псевдографику), то он будет испорчен безнадёжно: псевдографика обратится в буквы. Это может привести к принципиальной невозможности восстановить исходный текст. Перестановочный кодировщик перекодирует коды 4 и 5 в оставшиеся пустыми коды в образе:
Очевидно, это преобразование обратимо. И даже если мы неверно поняли кодировку исходного файла, всё равно есть шанс её восстановить. Всё что мы теряем в худшем случае - это информацию о перестановке букв, которую восстановить значительно легче, чем текст со слившимися буквами, что частая ситуация, особенно, когда файл в KOI-кодировке перекодируется по ошибке из кодировки WIN в ту же кодировку KOI. В заключение отмечу, что проблема с iconv заключается в том, что он пытается установить взаимно-однозначное сопоставление кодировок, которое, к сожалению, не имеет места (скажем, в win-1251 нет псевдографики, хотя в KOI-8 и ALT псевдографика присутствует). Поэтому iconv спотыкается и говорит, что преобразование невозможно.
6 Таблицы кодировокВ этом разделе мы приведём информацию о различных русских кодировках. В частичном виде она уже содержится в предыдущих разделах.cp866 : Так называемый альтернативный вариант = кодовая страница cp866 в MSDOS/IBM PCDOS. Буквы размещены так, чтобы сохранить место для графических рамок в приложениях DOS. Кодировка называется альтернативной, потому что была альтернативна другому набору, с русским алфавитом, занимавшими сплошной массив начиная с кода 128=0x80.
СПИСОК ЛИТЕРАТУРЫ
Содержание1 Введение2 Перекодировка вручную 2.1 Декодирование с помощью браузеров (IE, Netscape) 2.2 Импорт и экспорт кодовой страницы 866 в Word 2.3 Внутри файлового менеджера Far 2.4 Внутри редактора (X)Emacs (пакет russian.el) 3 Перекодировка с помощью внешней программы xcode.c 4 Перекодировка внутри программы (библиотека SRECODE) 4.1 На языке Perl 4.2 На языке Си 5 О перестановочной кодировке и iconv 6 Таблицы кодировок
|
|
©2002-2004 Редактор Дмитрий Хмелёв |