=> Главная База Знаний Qt Работа с unicode


Работа с unicode

Работа с unicode

Unicode является стандартной кодировкой, которая поддерживает большинство мировых систем записи. В основе кодировки Unicode лежит идея использования для хранения символов 16 бит, а не 8, и поэтому она позволяет закодировать примерно 65 000 символов вместо только 256[8]. Unicode содержит коды ASCII и ISO 8859-1 (Latin-1) в качестве своего подмножества с прежним их представлением. Например, английская буква «А» имеет значение 0x41 в кодировках ASCII, Latin-1 и Unicode, а буква «В» имеет значение 0xD1 в кодировках Latin-1 и Unicode. Класс Qt QString хранит строковые значения в кодировке Unicode. Каждый символ QString имеет 16-битовый тип QChar, а не 8-битовый тип char. Ниже приводятся два способа установки первого символа строки на значение «А»:

str[0] = 'A';

str[0] = QChar(0x41);

Если исходный файл имеет кодировку Latin-1, задавать символы Latin-1 очень легко:

str[0] = 'C';

Но если исходный файл имеет другую кодировку, хорошо срабатывает вариант с числовым кодом:

str[0] = QChar(0xD1);

Мы можем задать любой символ Unicode с помощью его числового кода. Например, ниже показано, как задается прописная буква «сигма» греческого алфавита («Σ») и символ валюты евро («€»):

str[0] = QChar(0x3A3);

str[0] = QChar(0x20AC);

Все числовые коды, поддерживаемые кодировкой Unicode, можно найти в сети Интернет по адресу http://www.unicode.org/standard/. Если вам приходится редко использовать символы Unicode, не относящиеся к Latin-1, для поиска их кодов вполне достаточно воспользоваться указанным адресом; но Qt обеспечивает более удобный способ ввода в программе Qt строк символов в кодировке Unicode, как мы увидим позднее в данном разделе.

Текстовый процессор в Qt 4 поддерживает на всех платформах следующие системы записи: арабскую, китайскую, кириллическую, греческую, иврит, японскую, корейскую, лаосскую, латинскую, тайскую и вьетнамскую. Он также поддерживает все скрипты 4.1 в кодировке Unicode, которые не требуют специальной обработки. Кроме того, в системе X11 с Fontconfig и в последних версиях системы Windows поддерживаются следующие языки: бенгальский, деванагари, гуйарати, гурмухи, каннада, кхмерский, малайский, сирийский, тамильский, телугу, тхаана (дивехи) и тибетский. Наконец, ория поддерживается в системе X11, а монгольский и синхала поддерживаются в Windows XP. Если в системе установлен соответствующий шрифт, Qt сможет воспроизвести текст на любом из этих языков. А при установке соответствующих программ ввода текста пользователи смогут вводить в своих приложениях Qt текст на этих языках.

Программирование с использованием QChar немного отличается от программирования с применением char. Для получения числового кода символа QChar вызовите для него функцию unicode(). Для получения кода ASCII переменной типа QChar (в виде char) вызовите функцию toLatin1(). Для символов, отсутствующих в кодировке Latin-1, функция toLatin1() возвращает '\0'.

Если нам заранее известно, что все строковые данные в программе представлены в кодировке ASCII или Latin-1, мы можем использовать такие стандартные функции (определенные в файле <cctype>), как isalpha(), isdigit() и isspace(), для обработки возвращаемого функцией toLatin1() значения. Однако в общем случае лучше использовать функции—члены класса QChar для выполнения этих операций, поскольку они будут правильно работать для любых символов Unicode. К таким функциям класса QChar относятся isPrint(), isPunct(), isSpace(), isMark(), isLetter(), isNumber(), isLetterOrNumber(), isDigit(), isSymbol(), isLower() и isUpper(). Например, ниже показано, как осуществлять проверку символа на цифру или прописную букву:

if (ch.isDigit() || ch.isUpper())

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

Строку в кодировке Unicode мы можем использовать в любом месте программного интерфейса Qt, где допускается применение строки типа QString. Qt сам отвечает за правильное ее отображение и преобразование в соответствущие кодировки при взаимодействии с операционной системой.

Особенно внимательными надо быть при чтении и записи текстовых файлов. Текстовые файлы могут использовать различные кодировки, и часто оказывается невозможным определить кодировку текстового файла по его содержанию. По умолчанию QTextStream использует локальную системную 8-битовую кодировку (которая доступна при помощи функции QTextCodec::codecForLocale()), как для чтения, так и для записи. Для стран Америки и Западной Европы это обычно подразумевает кодировку Latin-1.

Если мы разработали свой собственный формат файлов и собираемся считывать и записывать произвольные символы Unicode, мы можем сохранять данные в кодировке Unicode с помощью вызова

stream.setCodec("UTF-16");

stream.setGenerateByteOrderMark(true);

до начала записи в поток QTextStream. Данные в этом случае будут сохраняться в формате UTF-16, который использует два байта для представления одного символа и который будет иметь префикс из специального 16-битового значения (признак порядка байтов Unicode, 0xFFFE), указывающего на применение файлом кодировки Unicode и на прямой или обратный порядок байтов. Формат UTF-16 идентичен представлению в памяти строк QString, и поэтому чтение и запись представленных в кодировке Unicode строк в формате UTF-16 могут выполняться очень быстро. Однако такой подход связан с перерасходом памяти при сохранении данных, представленных целиком в кодировке ASCII, в формате UTF-16, поскольку в данном случае каждый символ займет два байта вместо одного.

Другие кодировки можно задавать путем вызова функции setCodec() с указанием соответствующего объекта преобразования QTextCodec. QTextCodec осуществляет преобразование между Unicode и заданной кодировкой. Объекты QTextCodec используются в различных контекстах в Qt. Внутренними средствами они применяются для поддержки шрифтов, методов ввода, буфера обмена, технологии «drag-and-drop» и названий файлов. Но мы можем их использовать и непосредственно при написании приложений Qt.

При чтении текстового файла QTextStream автоматически обнаруживает кодировку Unicode, если файл начинается с признака, определяющего порядок байтов. Такой режим работы можно отключить с помощью вызова setAutoDetectUnicode(false). Если нельзя рассчитывать на то, что данные начинаются с признака, определяющего порядок байтов, лучше всего перед чтением вызвать функцию setCodec() с аргументом «UTF-16».

Другой кодировкой, поддерживающей весь Unicode, является UTF-8. Его главное достоинство по сравнению с UTF-16, состоит в том, что он — супермножество по отношению к ASCII. Любой символ с кодом в диапазоне от 0x00 до 0x7F представляется в виде одного байта. Другие символы, включая символы Latin-1, код которых превышает значение 0x7F, представляются в виде последовательности из нескольких байтов. Текст, состоящий в основном из символов ASCII, в формате UTF-8 займет примерно вполовину меньше памяти, чем в формате UTF-16. Для применения UTF-8 с QTextStream перед чтением и записью сделайте вызов setEncoding(QTextStream::UnicodeUTF8).

Если мы всегда собираемся считывать и записывать файлы в кодировке Latin-1, вне зависимости от применяемой пользователем локальной кодировки, мы можем установить кодировку «ISO 8859-1» для потока QTextStream. Например:

QTextStream in(&file);

in.setCodec("ISO 8859-1");

При применении некоторых форматов файлов их кодировка задается в заголовке файла. Заголовок обычно представляется в простом виде в кодировке ASCII, чтобы обеспечить его правильное чтение вне зависимости от используемой кодировки (в предположении, что она является супермножеством по отношению к ASCII). Интересным примером таких форматов являются файлы XML. Обычно файлы XML представлены в кодировке UTF-8 или UTF-16. Для правильного их чтения необходимо вызвать функцию setCodec() с «UTF-8». Если используется формат UTF-16, QTextStream автоматически обнаружит это и настроится на него. Заголовок <?xml?> файла XML иногда содержит аргумент encoding, например:

<?xml version="1.0" encoding="EUC-KR"?>

Поскольку QTextStream не позволяет менять кодировку после начала чтения, чтобы учесть явно заданную кодировку, придется заново прочитать файл, задавая правильное преобразование (полученное функцией QTextCodec::codecForName()). В случае файла XML мы можем сами не делать преобразование кодировок, воспользовавшись классами Qt, предназначенными для XML и описанными в главе 15.

Другое применение объектов QTextCodec заключается в указании кодировки строк в исходном коде. Давайте рассмотрим пример, когда группа японских программистов создает приложение, предназначенное главным образом для применения на японском рынке. Эти программисты, вероятно, будут писать свой исходный программный код в текстовом редакторе, использующем такие кодировки, как EUC-JP или Shift-JIS. Такой редактор позволяет им вводить японские иероглифы непосредственно, и, например, они смогут написать следующий код:

QPushButton *button = new QPushButton(tr("♦♦"));

По умолчанию Qt считает, что аргументы функции tr() задаются в кодировке Latin-1. Для изменения этого необходимо вызвать статическую функцию QTextCodec::setCodecForTr(). Например:

QTextCodec *japaneseCodec = QTextCodec::codecForName("EUC-JP");

QTextCodec::setCodecForTr(japaneseCodec);

Это должно быть сделано до первого вызова tr(). Обычно мы делаем это в функции main() непосредственно после создания объекта QApplication.

Другие используемые в программе строки будут по-прежнему интерпретироваться как строки, представленные в кодировке Latin-1. Если программисты хотят вводить японские иероглифы и здесь, они могут явно преобразовывать их в Unicode, используя объект QTextCodec:

QString text = japaneseCodec->toUnicode("♦♦♦♦♦");

Можно поступить по-другому и указать Qt на необходимость применения особого преобразования между типами const char * и QString путем вызова функции QTextCodec::setCodecForCStrings():

QTextCodec::setCodecForCStrings(QTextCodec::codecForName("EUC-JP"));

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

Ниже приводится список кодировок, поддерживаемых Qt 4:

• Apple Roman

• Big5

• Big5-HKSCS

• EUC-JP

• EUC-KR

• GB18030-0

• IBM 850

• IBM 866

• IBM 874

• ISO 2022-JP

• ISO 8859-1

• ISO 8859-2

• ISO 8859-3

• ISO 8859-4

• ISO 8859-5

• ISO 8859-6

• ISO 8859-7

• ISO 8859-8

• ISO 8859-9

• ISO 8859-10

• ISO 8859-13

• ISO 8859-14

• ISO 8859-15

• ISO 8859-16

• Iscii-Bng

• Iscii-Dev

• Iscii-Gjr

• Iscii-Knd

• Iscii-Mlm

• Iscii-Ori

• Iscii-Pnj

• Iscii-Tlg

• Iscii-Tml

• JIS X 0201

• JIS X 0208

• KOI8-R

• KOI8-U

• MuleLao-1

• ROMAN8

• Shift-JIS

• TIS-620

• TSCII

• UTF-8

• UTF-16

• UTF-16BE

• UTF-16LE

• Windows-1250

• Windows-1251

• Windows-1252

• Windows-1253

• Windows-1254

• Windows-1255

• Windows-1256

• Windows-1257

• Windows-1258

• WINSAMI2

Для всех этих кодировок функция QTextCodec::codecForName() всегда будет возвращать достоверный указатель. Другие кодировки можно обеспечить путем создания подкласса QTextCodec.