Delphi в мире Юникода

         

Delphi и кодировка Unicode Часть


Nick Hodges, Embarcadero
Перевод: Виктор Роднев, www.interface.ru
Оригинал: Delphi in a Unicode World Part II: New RTL Features and Classes to Support Unicode

В данной статье рассматриваются новые функции библиотеки Tiburon Runtime Library, которые помогают обрабатывать строки Unicode.



Дополнительная поддержка Unicodeбиблиотекой RTL


В библиотеку RTL добавлен ряд подпрограмм, которыми поддерживается использование строк Unicode.



Другие функции библиотеки RTL, связанные с кодировкой Unicode


Есть ряд других подпрограмм для преобразования строк из одной кодовой страницы в другую. В их числе: UnicodeStringToUCS4String UCS4StringToUnicodeString UnicodeToUtf8 Utf8ToUnicode

Кроме того, в библиотеке RTL также появился тип RawByteString, который представляет собой тип строки, не связанный ни с какой кодировкой:   RawByteString = type AnsiString($FFFF);

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

Как правило, присвоения типов строк совместимы друг с другом.

Например, присвоение MyUnicodeString := MyAnsiString;

будет выполнено, как и ожидалось - содержимое строки типа AnsiString будет помещено в строку типа UnicodeString. Как правило, можно присваивать один тип строки строке другого типа, и компилятор выполнит необходимые преобразования, если возможно.

Однако некоторые преобразования могут привести к потере данных, и необходимо остерегаться при перемещении из строки одного типа, которая включает данные в кодировке Unicode, в другую, тип которой не поддерживает Unicode. Например, можно присваивать тип UnicodeString строке типа AnsiString, но если строка типа UnicodeString содержит символы, которые не отображаются в активной в данный момент кодовой странице ANSI, то эти символы будут потеряны при преобразовании. Рассмотрим следующий код: procedure TForm88.Button4Click(Sender: TObject); var   U: UnicodeString;   A: AnsiString; begin   U := 'This is a UnicodeString';   A := U;   Memo1.Lines.Add(A);   U := 'Добро пожаловать в мир Юникода с использованием Дельфи 2009!!';   A := U;   Memo1.Lines.Add(A); end;

Результат выполнения этого кода, если текущая кодовая страница ОС - 1252, будет следующим: This is a UnicodeString ????? ?????????? ? ??? ??????? ? ?????????????? ?????? 2009!!

Как можно видеть, при назначении типа UnicodeString строке типа AnsiString информация теряется,  так как символы кириллицы не отображаются кодовой страницей Windows-1252. Причина такого результата - строка UnicodeString содержала символы, не представимые в кодовой странице AnsiString, эти символы были потеряны и заменены вопросительными знаками при назначении типа UnicodeString строке типа AnsiString.



Класс TCharacter




Библиотека Tiburon RTL включает новый класс TCharacter, который описывается в модуле Character. Это закрытый класс, который полностью состоит из статичных функций класса. Разработчикам не следует создавать экземпляры класса TCharacter, предпочтительнее просто вызывать его статические методы класса напрямую. Функции этого класса позволяют, в числе прочего, выполнять: преобразование символов в верхний или нижний регистр; определение типа данного символа, то есть является ли символ буквой, цифрой, знаком препинания и так далее.

Классом TCharacter используются стандарты, установленные организацией Unicode consortium.

Разработчики могут использовать класс TCharacter для выполнения многих действий, выполнявшихся до этого с наборами символов. Например, следующий программный код: uses Character; begin if MyChar in ["a"..."z", "A"..."Z"] then begin   ... end; end; можно легко заменить кодом: uses   Character; begin if TCharacter.IsLetter(MyChar) then begin     ... end; end;

Модуль Character содержит также ряд автономных функций, которые выполняют функции каждой из функций класса TCharacter, так что если предпочтительнее простой вызов функции, приведенный выше программный код можно переписать как: uses   Character; begin if IsLetter(MyChar) then begin     ... end; end;

Таким образом, класс TCharacter можно использовать для выполнения многих действий или проверки символов, которая может понадобиться.

Кроме того, класс TCharacter содержит методы класса, позволяющие определить, является ли символ верхним или нижним суррогатом суррогатной пары.



Класс TEncoding


Библиотека Tiburon RTL также включает новый класс TEncoding. Его назначение - определить конкретный тип кодировки символов, чтобы можно было сообщить библиотеке VCL, какой тип кодировки необходимо использовать в конкретных ситуациях.

Например, пусть есть экземпляр TStringList, содержащий текст, который необходимо записать в файл. Ранее необходимо было бы написать begin   ...   MyStringList.SaveToFile("SomeFilename.txt");    ... end;

и файл записался бы, по умолчанию, в кодировке ANSI. Данный код по-прежнему хорошо работает - файл запишется им в кодировке ANSI, как и раньше, но теперь, когда в Delphi поддерживаются строковые данные в кодировке Unicode, разработчикам может потребоваться записать строковые данные в какой-либо конкретной кодировке. Поэтому оператор SaveToFile (а также LoadFromFile) теперь имеет дополнительный второй параметр, которым определяется используемая кодировка: begin   ...   MyStringList.SaveToFile("SomeFilename.txt", TEncoding.Unicode);    ... end;

При выполнении приведенного выше кода файл будет записан как текстовый файл в кодировке Unicode (UTF-16).

Классом TEncoding будет также преобразовываться заданный набор байтов из одной кодировки в другую, извлекаться информация о байтах и/или символах в заданной строке или массиве символов, преобразовываться любая строка в массив array of byte (TBytes) и выполняться другие функции, которые могут потребоваться для конкретной кодировки заданной строки или заданного массива символов.

Класс TEncoding включает следующие свойства класса, дающие доступ к экземпляру TEncoding заданной кодировки:     class property ASCII: TEncoding read GetASCII;     class property BigEndianUnicode: TEncoding read GetBigEndianUnicode;     class property Default: TEncoding read GetDefault;     class property Unicode: TEncoding read GetUnicode;     class property UTF7: TEncoding read GetUTF7;     class property UTF8: TEncoding read GetUTF8;

Свойство Default ссылается на активную кодовую страницу ANSI. Свойство Unicode ссылается на UTF-16.

Класс TEncoding также включает функцию class function TEncoding.GetEncoding(CodePage: Integer): TEncoding;

которая будет возвращать экземпляр TEncoding, соответствующий кодовой странице, переданной в параметре.

Кроме того, он включает следующую функцию: function GetPreamble: TBytes;

которая будет возвращать правильный маркер порядка байтов для заданной кодировки.

Класс TEncoding также представляет собой интерфейс, совместимый с классом .Net Encoding.



Получение массива байтов TBytesиз строк


В составе библиотеки RTL есть также набор перегружаемых подпрограмм для извлечения из строки массива байтов. Как будет показано в , рекомендуется использовать в качестве буфера данных массив TBytes, а не строку. Библиотека RTL упрощает это за счет перегружаемых версий функции BytesOf(), принимающей в качестве параметра разные типы строк.



SetCodePage


Функция SetCodePage, объявленная в модуле System.pas как procedure SetCodePage(var S: AnsiString; CodePage: Word; Convert: Boolean);

представляет собой новую функцию RTL, которой задается новая кодовая страница для строки типа AnsiString. Необязательным параметром Convert определяется, следует ли преобразовать сами данные строки в заданную кодовую страницу. Если значение параметра Convert - False, то для строки просто будет изменена кодовая страница. Если значение параметра Convert - True, то данные передаваемой строки будут преобразованы в заданную кодовую страницу.

Функция SetCodePage должна использоваться редко и с большой осторожностью. Обратите внимание, что, если кодовая страница не соответствует существующим данным строки (то есть значение параметра Convert  - False), то результаты могут оказаться непредсказуемыми. Кроме того, если существующие данные строки преобразованы, а в новой кодовой странице не представлен заданный исходный символ, данные могут потеряться.



StringCodePage


Подпрограммой StringCodePage будет возвращаться значение Word, которое соответствует кодовой странице для заданной строки.

Рассмотрим следующий код: procedure TForm88.Button2Click(Sender: TObject); type   // Кодовая страница для ANSI-кириллицы - 1251   CyrillicString = type AnsiString(1251); var   A: AnsiString;   U: UnicodeString;   U8: UTF8String;   C: CyrillicString; begin   A := 'This is an AnsiString';   Memo1.Lines.Add('AnsiString Codepage: ' + IntToStr(StringCodePage(A)));   U := 'This is a UnicodeString';   Memo1.Lines.Add('UnicodeString Codepage: ' + IntToStr(StringCodePage(U)));   U8 := 'This is a UTF8string';   Memo1.Lines.Add('UTF8string Codepage: ' + IntToStr(StringCodePage(U8)));   C := 'This is a CyrillicString';   Memo1.Lines.Add('CyrillicString Codepage: ' + IntToStr(StringCodePage(C))); end;

Результатом выполнения приведенного выше кода будет: The Codepage for an AnsiString is: 1252 The Codepage for an UnicodeString is: 1200 The Codepage for an UTF8string is: 65001 The Codepage for an CyrillicString is: 1251



StringElementSize


Подпрограммой StringElementSize возвращается типичный размер элемента (элемента кода) в заданной строке. Рассмотрим следующий код: procedure TForm88.Button3Click(Sender: TObject); var   A: AnsiString;   U: UnicodeString; begin   A := 'This is an AnsiString';   Memo1.Lines.Add('The ElementSize for an AnsiString is: ' + IntToStr(StringElementSize(A)));   U := 'This is a UnicodeString';   Memo1.Lines.Add('The ElementSize for an UnicodeString is: ' + IntToStr(StringElementSize(U))); end;

Результатом выполнения приведенного выше кода будет: The ElementSize for an AnsiString is: 1 The ElementSize for an UnicodeString is: 2



TStringBuilder


Библиотека RTL теперь включает класс TStringBuilder. Его назначение ясно из его названия - это класс, предназначенный для создания строк. Класс TStringBuilder содержит большое количество перегружаемых функций для добавления, замены и вставки содержимого в заданную строку.  Этот класс упрощает создание единых строк из множества различных типов данных. Каждая из функций Append, Insert и Replace возвращает экземпляр класса TStringBuilder, поэтому их можно легко объединять для создания единой строки.

Например, можно использовать класс TStringBuilder вместо усложненного оператора Format. Например, можно написать следующий программный код: procedure TForm86.Button2Click(Sender: TObject); var   MyStringBuilder: TStringBuilder;   Price: double; begin   MyStringBuilder := TStringBuilder.Create('');   try     Price := 1.49;     Label1.Caption := MyStringBuilder.Append('The apples are $').Append(Price).              AAppend(' a pound.').ToString;   finally     MyStringBuilder.Free;   end; end;

Класс TStringBuilder также представляет собой интерфейс, совместимый с классом .Net StringBuilder.

Объявление новых типов строк

Компилятор Tiburon позволяет объявить собственный тип строки, связанный с заданной кодовой страницей. Доступно любое число кодовых страниц. Например, если необходим тип строки, соответствующий кодировке ANSI-кириллице, можно объявить: type   // Кодовая страница для ANSI-кириллицы - 1251   CyrillicString = type Ansistring(1251);

И новый тип строки будет соответствовать кодовой странице кириллицы.




В было показано, какие выгоды дает разработчикам на Delphi поддержка кодировки Unicode, позволяя работать со всеми наборами символов в кодировке Unicode. Были рассмотрены основные особенности типа строки UnicodeString и было показано, как его можно использовать в Delphi.
В части II будет рассказано о некоторых новых функциях библиотеки Delphi Runtime Library, предназначенных для поддержки Unicode, и общих методах обработки строк.


Библиотека Tiburon' s Runtime Library теперь полностью поддерживает новый тип строки UnicodeString. В нее входят новые классы и подпрограммы для обработки и преобразования строк в кодировке Unicode, для управления кодовыми страницами и для упрощения перехода с более ранних версий.
В будут рассмотрены специальные кодовые конструкции, которые необходимы, чтобы выяснить: готов ли тот или иной программный код к переходу на кодировку Unicode.