Как известно, в Haskell есть "полная поддержка уникода". Настало время выяснить, что же это означает.
1. Внутренний тип данных Char представляет из себя unicode code point. То есть, в нём можно хранить любой символ, предусмотренный уникодом. Осталось выяснить, как его туда положить и вытащить обратно.
2. Парсер GHC устроен так, что работает в кодировке UTF-8. То есть, если в исходном коде задавать имена и строковые константы в UTF-8, GHC их поймёт правильно.
3. Для преобразования строк при вводе-выводе используются
три библиотеки и Data.ByteString.
4. Data.ByteString - это, грубо говоря, строка из привычных нам восьмибитных байтов. Для неё перегружен ввод-вывод - определены стандартные функции: getLine, putStrLn, interact и т.д.
5. Консольный ввод-вывод делается байтами, а не уникодами, поэтому, при выводе String происходит либо обрезание кода символов до младших 8(7?) бит либо escaping(экранирование).
6. При выводе русских строк их надо преобразовать к нужной кодировке:
7. Библиотека
Data.Encoding. Написана на хаскеле, кодировки представляют из себя абстрактный тип данных, принадлежащий классу Encoding и подключаются модулями, например,
Data.Encoding.KOI8R. Также можно определять кодировку динамически, с помощью функции encodingFromString. Интерфейс очень простой:
encode::(Encoding enc)=>enc->String->ByteString
decode::(Encoding enc)=>enc->ByteString->String
Есть также функции для работы с lazy bytestring и recode.
-------
В Data.Encoding.KOI8R, видимо, ошибка: Data.ByteString.putStrLn $ encode KOI8R myStr where myStr="русская строка" выдаёт транслитерацию, (decode KOI8R (encode KOI8R myStr) == myStr) = False.
(decode CP1251 (encode CP1251 myStr) == myStr) = True, putStrLn $ encode CP1251 myStr печатает нормально. С UTF8 тоже всё хорошо, а кодировки IBM866 в библиотеке Data.Encoding нет.
При установленном LANG=ru_RU.KOI8-R функция getSystemEncoding возвращает KOI8R, а при LANG=ru_RU.CP1251 она, почему-то, возвращает ASCII. Проверять, в библотеке или в моей системе проблемы, было лень.
-------
Итог: интерфейс очень удобный, но KOI-8 не работает, а хочется, чтобы было всё.
8. Библиотека
UTF8-string.
Интерфейс:
encodeString::String->String
decodeString::String->String
encode::String->[Word8]
decode::String->[Word8]
Поддерживает только одну кодировку, при использовании предлагает либо строгую типизацию (encode/decode), либо простоту(encodeString/decodeString) - уникоды и байты хранятся в одинаковом типе String.
-------
Она нам ещё пригодится.
9. Билиотека
Codec.Text.IConv. Представляет из себя обёртку вокруг libiconv.
Интерфейс:
convert::EncodingName->EncodingName->Byt
eString->ByteString.
Есть также функции для проверки, что можно перекодировать, а что нельзя, и т.п.
Для использования необходимо как-то получить ByteString. Немного поразбиравшись, взял библиотеку UTF8-string. Итоговый код:
import Data.ByteString.Lazy
import Codec.Text.IConv
import Data.ByteString.Lazy.UTF8
myStr="это - строка по-русски "
main = Data.ByteString.Lazy.putStrLn $ convert "UTF-8" "KOI8-R" $ Data.ByteString.Lazy.UTF8.fromString myStr
Работает.
Достоинства: iconv знает много разнообразных кодировок. Недостатки: библиотека системно-зависимая - при отсутствии в libiconv необходимой кодировки вылетает исключение. Что и было продемонстрировано по просьбе преобразовать из "UTF8" в "KOI8-R". а у автора библиотеки (irc://irc.freenode.net:6667#haskell:dco
utts) система знала эту кодировку под обоими именами: "UTF8" и "UTF-8".
Возможно, в ближайшем будущем буду пробовать получать русские буквы через HTTP.
ОБН: Автор библиотеки Data.Encoding ответил, что про баг с декодированием КОИ-8 он знает и в darcs он исправлен, сейчас идёт большой редизайн, и следующая версия библиотеки будет пуще прежнего.