Ё

Русская фантастика >> Книжная полка >> Ё >> История | Кодировки | Поддержка | xcode | Этюды | Мнения | Конфузы | ЧаВО | Пресса

 

Корректная обработка кодировок с буквой Ё

Корректная обработка кодировок с буквой Ё

Д.В. Хмелёв

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) и справочную (раздел 6).

Перекодировку иногда удобно осуществлять вручную, то есть, набрав последовательность команд в какой-нибудь оболочке, позволяющей проводить перекодировку. Иногда (в частности, при пакетной обработке файлов) перекодировку удобно осуществлять с помощью вызова внешних программ. Третий случай, когда может потребоваться перекодировка - это перекодировка внутри программы, когда необходим некоторый программный код, обрабатывающий данные. Все эти способы рассмотрены в следующих разделах.

В разделе 2 описано, как можно перекодировать тексты из одной кодировки в другую вручную в широко распространённых программных средствах. Отметим, что все эти способы обеспечивают лишь сохранение букв русского алфавита, то есть эти перекодировки не являются перестановочными.

Разделы 3 и 4 посвящены реализации перестановочной перекодировки.

Автор признателен Андрею Бирюку за подсказанную идею перестановочной перекодировки. Автор также признателен Сергею Скотникову за конструктивное замечание.

2  Перекодировка вручную

Заранее просим прощения у читателя, который сочтёт нижеприведённые советы очевидными. Напротив, настоящий текст задумывался как всем понятный справочник по перекодировке. Поэтому, если вам что неясно - не обвиняйте себя в непонятливости, напишите по адресу, приведённому в конце страницы.

Разумеется, здесь упомянуты не все возможные способы. Мы концентрируемся в первую очередь на тех способах, которые проверены на сохранение буквы Ё при перекодировке. Если кто-то обладает замечательной программой перекодировки, которая поддерживает букву Ё, но здесь не упомянута, то немедленно сообщите об этом по адресу, приведённому в конце страницы.

2.1  Декодирование с помощью браузеров (IE, Netscape)

В большинстве систем можно попытаться запустить браузер и открыть в нём через следующее меню искомый файл с неясной кодировкой.

Netscape NavigatorFile/Open Page ® Choose file...
Internet ExplorerFile/Open... ® Browse...
Затем через меню можно попытаться выбрать одну из 4-5 кириллических кодировок, и получить (при удаче) правильный результат.

Netscape NavigatorView/Character set
Internet ExplorerEdit/Encoding

Замечания. В большинстве систем под 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 - читайте

C:\Program Files\Far\License.xUSSR.txt
имеет встроенную поддержку двух кодировок Alt и win-cp1251, которые называются DOS и Win. В стандартном текстовом редакторе (вызываемом нажатием на кнопку < F4 > ) переключаться между этими кодировками можно по клавише < F8 > . Набор кодировок можно расширить, добавив в реестр файлы из директории

C:\Program Files\Far\Addons\Tables\Russian
Чтобы, например, добавить кодировку KOI-8 необходимо перейти в указанную директорию, запустить нажатием на < Enter > файл KOI8-r.reg и согласиться на добавление информации из этого файла в реестр. Теперь можно в редакторе выбрать нужную кодировку с помощью нажатия < Alt > + < F8 > . Можно поставить последовательное переключение кодировок на клавишу < F8 > , добавив в реестр файл

C:\Program Files\Far\Addons\Macros\F9Table.reg

Чтобы перекодировать файл (или его фрагмент) из одной кодировки в другую, необходимо выполнить следующие действия:

  1. Открыть файл в редакторе командой < F4 > .
  2. Переключиться в исходную кодировку.
  3. Удерживая < Shift > и перемещая курсор, выделить необходимый фрагмент файла (весь файл выделяется командой < Ctrl > + < A > ).
  4. Переместить файл в буфер обмена командой < Shift > + < Del >
  5. Переключиться в нужную кодировку (с помощью < F8 > или < Alt > + < F8 > или < F9 > ).
  6. Вставить исходный фрагмент из буфера < Shift > + < Del > .

Заметим также, что в оболочке Far возможно автоматическое определение кодировки при открытии файла для просмотра или редактирования. Необходимую опцию необходимо проставить в опциях редактора и программы просмотра.

2.4  Внутри редактора (X)Emacs (пакет russian.el)

Напомним, что в редакторе (X)Emacs (см. раздел Поддержка) под комбинацией M- < буква > подразумевается обычно комбинация клавиш < Alt > + < буква > . На клавиатурах в Sun-системах роль M исполняет клавиша Meta слева от пробела с изображённым на ней ромбиком. Если ни Alt ни Meta нет, то можно комбинацию M- < буква > набирать последовательным нажатием клавиш < Esc > и < буква >

При правильно настроенном пакете russian.el (см. также внешнюю ссылку) перекодировка осуществляется набором

M-x russian-translate-buffer или M-x russian-translate-region
в зависимости от того, надо ли перекодировать весь файл или только выделенную его часть. Затем необходимо выбрать исходную кодировку и нужную кодировку. Чтобы получить список всех доступных кодировок необходимо на приглашении в мини-буфере нажать клавишу < Tab > . Кстати говоря, нажатие на клавишу < Tab > сокращает и время набора приведённых команд.

Чтобы отобразить файл в нужной кодировке необходимо набрать

M-x russian-display
и выбрать нужную кодировку.

Пакет russian.el способен также определять автоматически тип кодировки. Для этого необходимо выполнить команду

M-x russian-detect-or-get-encoding

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
код12345
букваАБВ**

Кодировка 2
код12345
буква*А*БВ

То есть, в первой кодировке код А - 1, а во второй код А - 2 и т.д.

Обычный перекодировщик из первой кодировки во вторую коду 1 сопоставляет код 2, коду 2 коду 4, коду 3, код 5. Коды 4 и 5 остаются на месте. Итого


1 ® 2


2 ® 4


3 ® 5


4 ® 4


5 ® 5

Очевидно, буквы с коды 2 и 4 отображаются в один код - 4. Таким образом, если на входе был бинарный файл (содержащий не только символы алфавита, а например, ещё и псевдографику), то он будет испорчен безнадёжно: псевдографика обратится в буквы.

Это может привести к принципиальной невозможности восстановить исходный текст.

Перестановочный кодировщик перекодирует коды 4 и 5 в оставшиеся пустыми коды в образе:


1 ® 2

2 ® 4

3 ® 5

4 ® 1
(*)

5 ® 3
(*)

Очевидно, это преобразование обратимо. И даже если мы неверно поняли кодировку исходного файла, всё равно есть шанс её восстановить. Всё что мы теряем в худшем случае - это информацию о перестановке букв, которую восстановить значительно легче, чем текст со слившимися буквами, что частая ситуация, особенно, когда файл в KOI-кодировке перекодируется по ошибке из кодировки WIN в ту же кодировку KOI.

В заключение отмечу, что проблема с iconv заключается в том, что он пытается установить взаимно-однозначное сопоставление кодировок, которое, к сожалению, не имеет места (скажем, в win-1251 нет псевдографики, хотя в KOI-8 и ALT псевдографика присутствует). Поэтому iconv спотыкается и говорит, что преобразование невозможно.

6  Таблицы кодировок

В этом разделе мы приведём информацию о различных русских кодировках. В частичном виде она уже содержится в предыдущих разделах.

cp866 : Так называемый альтернативный вариант = кодовая страница cp866 в MSDOS/IBM PCDOS. Буквы размещены так, чтобы сохранить место для графических рамок в приложениях DOS. Кодировка называется альтернативной, потому что была альтернативна другому набору, с русским алфавитом, занимавшими сплошной массив начиная с кода 128=0x80.

& 0123456789ABCDEF
8xАБВГДЕЖЗИЙКЛМНОП
9xРСТУФХЦЧШЩЪЫЬЭЮЯ
Axабвгдежзийклмноп
Bx                
Cx                
Dx                
Exрстуфхцчшщъыьэюя
FxЁё              



cp1251 : MS Windows кодовая страница 1251. Используется в качестве внутренней кодировки локализаций MS Windows.

& 0123456789ABCDEF
8x                
9x                
Ax        Ё       
Bx        ё       
CxАБВГДЕЖЗИЙКЛМНОП
DxРСТУФХЦЧШЩЪЫЬЭЮЯ
Exабвгдежзийклмноп
Fxрстуфхцчшщъыьэюя



koi8-r : KOI-8 RFC 1489 = старый KOI-8 ГОСТ 19768-74 с добавленными «ё» и «Ё». Используется в эхо-конференциях и при пересылке электронной почты.

& 0123456789ABCDEF
8x                
9x                
Ax   ё            
Bx   Ё            
Cxюабцдефгхийклмно
Dxпярстужвьызшэщчъ
ExЮАБЦДЕФГХИЙКЛМНО
FxПЯРСТУЖВЬЫЗШЭЩЧЪ



iso8859-5 : Стандарт ГОСТ. В силу этого недоразумения используется в «фирменных» локализациях систем Sun и Hewlett Packard.

& 0123456789ABCDEF
8x                
9x                
Ax Ё              
BxАБВГДЕЖЗИЙКЛМНОП
CxРСТУФХЦЧШЩЪЫЬЭЮЯ
Dxабвгдежзийклмноп
Exрстуфхцчшщъыьэюя
Fx ё              



mac : Кодировка, используемая в компьютерах Macintosh. Обратите внимание на пострадавшую за код 0xFF букву «я»

& 0123456789ABCDEF
8xАБВГДЕЖЗИЙКЛМНОП
9xРСТУФХЦЧШЩЪЫЬЭЮЯ
Ax                
Bx                
Cx                
Dx             Ёёя
Exабвгдежзийклмноп
Fxрстуфхцчшщъыьэю 



osn : Некий «основной вариант» (единственное отличие от iso8859-5 в заглавной Ё)

& 0123456789ABCDEF
8x                
9x                
Ax                
BxАБВГДЕЖЗИЙКЛМНОП
CxРСТУФХЦЧШЩЪЫЬЭЮЯ
Dxабвгдежзийклмноп
Exрстуфхцчшщъыьэюя
FxЁё              



moshkov : Кодировка машины Besta (http://www.osp.ru/museum/story/24_00.htm), выжившая до 2002 г в качестве внутренней кодировки библиотеки М.Мошкова http://www.lib.ru. Устарела. Теперь в качестве внутренней кодировки на www.lib.ru используется KOI8-R

& 0123456789ABCDEF
8x                
9x                
Ax   ё        Ъ ъ 
Bx   Ё            
CxЮАБЦДЕФГХИЙКЛМНО
DxПЯРСТУЖВЬЫЗШЭЩЧ 
Exюабцдефгхийклмно
Fxпярстужвьызшэщч 



sort : Таблица, которую можно использовать для корректной сортировки файла по алфавиту

& 0123456789ABCDEF
8xАБВГДЕЁЖЗИЙКЛМНО
9xПРСТУФХЦЧШЩЪЫЬЭЮ
AxЯабвгдеёжзийклмн
Bxопрстуфхцчшщъыьэ
Cxюя              
Dx                
Ex                
Fx                



alt-fido : Кодировка с заменой букв Н и р на похожие по написанию латинские буквы H (аш или эйч) и p (пэ или пи). Использовалась в связи с тем, что некоторые популярные зарубежные редакторы не воспринимали указанные русские буквы (GoldEd, используемый в FIDOnet, внутренний редактор ранних не русифицированных версий Norton Commander, редакторы полей в базах данных FoxPro, DBx и т.д.). Поскольку многие тексты распространялись именно через FIDO, а при перекодировке эта «особинка» сохраняется, в современных электронных библиотеках некоторые тексты содержатся в клонах этой кодировки koi8-r-fido, cp1251-fido и так далее... Любопытно, как выходили бы из положения наши умельцы, если бы соответствующая буква не была похожа на какую-нибудь латинскую?

& 0123456789ABCDEF
0x                
1x                
2x                
3x                
4x        Н       
5x                
6x                
7xр               
8xАБВГДЕЖЗИЙКЛМ ОП
9xРСТУФХЦЧШЩЪЫЬЭЮЯ
Axабвгдежзийклмноп
Bx                
Cx                
Dx                
Ex стуфхцчшщъыьэюя
FxЁё              



koi7 : Таблица koi8-r с обнулённым старшим битом. Русские буквы оказываются на месте созвучных латинских и письмо покорёженное таким способом всё ещё можно прочесть (если только в нём не встречается заглавный твёрдый знак Ъ, который после преобразования в код 7F приводит в ступор некоторые почтовые системы. На самом деле

абвгдеёжзийклмнопрстуфхцчшщъыьэюя = ABWGDE#VZIJKLMNOPRSTUFHC^[]_YX\@Q
и

АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ = abwgde$vzijklmnoprstufhc~{}ÿx|`q

& 0123456789ABCDEF
0x                
1x                
2x  ЪёЁ           
3x                
4xюабцдефгхийклмно
5xпярстужвьызшэщчъ
6xЮАБЦДЕФГХИЙКЛМНО
7xПЯРСТУЖВЬЫЗШЭЩЧ 
8x                
9x                
Ax                
Bx                
Cx                
Dx                
Ex                
Fx                



dkoi : DKOI-8 (русский EBCDIC) ГОСТ 19768-87, устарела.

& 0123456789ABCDEF
0x                
1x                
2x                
3x                
4x  Ё             
5x         ё      
6x                
7x     Ъюаб       
8xц         дефгхи
9xй         клмноп
Axя         рстужв
BxьызшэщчъЮАБЦДЕФГ
Cx          ХИЙКЛМ
Dx          НОПЯРС
Ex          ТУЖВЬЫ
Fx          ЗШЭЩЧ 



cp500 : Кодовая страница CECP 500, устарела.

& 0123456789ABCDEF
0x                
1x                
2x                
3x                
4x  тфрсухчё      
5x щъышэюяьп      
6x  ТФРСУХЧб      
7x ЩЪЫШЭЮЯЬ       
8xи          Л   Б
9xА          КцИЦ 
AxЕ         ЁПано 
Bx   З  ЖМНО    Дз
Cx                
Dx          Й     
Ex          Вджвге
Fx          Глмйк 



ebcdic : EBCDIC ГОСТ 19768-74, устарела.

& 0123456789ABCDEF
0x                
1x                
2x                
3x                
4x  Ё             
5x        АБ      
6x  ВГДЕЖЗИЙ      
7xКЛМНОПРСТ       
8xУ         ФХЦЧШЩ
9xЪ         ЫЬЭЮЯа
Axб         вгдежз
Bxийклмнопрстуфхцч
Cx          шщъыьэ
Dx          юя ё  
Ex                
Fx                



ascii : Фонетическая раскладка клавиатуры при вводе русских букв. Используется в пакете russian.el русификации (X)Emacs. На самом деле

абвгдеёжзийклмнопрстуфхцчшщъыьэюя = abwgde^vzijklmnoprstufhc=[]#yx\`q
и

АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ = ABWGDE&VZIJKLMNOPRSTUFHC+{}$YX|~Q

& 0123456789ABCDEF
0x                
1x                
2x   ъЪ Ё    Ч    
3x             ч  
4x АБЦДЕФГХИЙКЛМНО
5xПЯРСТУЖВЬЫЗшэщё 
6xюабцдефгхийклмно
7xпярстужвьызШЭЩЮ 
8x                
9x                
Ax                
Bx                
Cx                
Dx                
Ex                
Fx                



СПИСОК ЛИТЕРАТУРЫ

[1]
A. Chernov. Registration of a Cyrillic Character Set. RFC 1489, RELCOM Development Team, July 1993. см. также главный сетевой ресурс про КОИ8.

[2]
J. Reynolds, J. Postel. Assigned Numbers. RFC 1700, USC/Information Sciences Institute, October 1994.

[3]
T.Greenwood, J. H. Jenkins. ISO 8859-5 (1988) to Unicode. Unicode Inc. January 1995.

[4]
M. Siugnard, L. Hoerth. cp1251_WinCyrillic to Unicode table. Unicode Inc. March 1995.

[5]
Л.Н. Знаменская, С.В. Знаменский. Проблема множественности русских кодировок и новое семейство кириллических шрифтов. http://rustex.botik.ru/znamensk/recode/, см. также локальную копию.

Содержание

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  Таблицы кодировок

Русская фантастика >> Книжная полка >> Ё >> История | Кодировки | Поддержка | xcode | Этюды | Мнения | Конфузы | ЧаВО | Пресса


©2002-2004 Редактор Дмитрий Хмелёв
©2002-2004 Русская фантастика, гл.ред Дмитрий Ватолин
©2002 Рисунок Владимир Савватеев