Delphi и кодировка Unicode, часть II: Новые функции библиотеки RTL и классы для поддержки кодировки Unicode

Источник: embarcadero

Автор: Виктор Роднев ©

Воспроизведение и распространение данной статьи возможно при условии установки прямой ссылки на данный портал

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

Введение

В части I было показано, какие выгоды дает разработчикам на Delphi поддержка кодировки Unicode, позволяя работать со всеми наборами символов в кодировке Unicode. Были рассмотрены основные особенности типа строки UnicodeString и было показано, как его можно использовать в Delphi.

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

Класс 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.

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).

             ÄAppend(' a pound.').ToString;

  finally

    MyStringBuilder.Free;

  end;

end;

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

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

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

type

  // Кодовая страница для ANSI-кириллицы - 1251

  CyrillicString = type Ansistring(1251);

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

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

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

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

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

Другие функции библиотеки 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.

SetCodePage

Функция SetCodePage, объявленная в модуле System.pas как

procedure SetCodePage(var S: AnsiString; CodePage: Word; Convert: Boolean);

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

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

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

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

Заключение

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

В части III будут рассмотрены специальные кодовые конструкции, которые необходимы, чтобы выяснить: готов ли тот или иной программный код к переходу на кодировку Unicode.


Страница сайта http://www.interface.ru
Оригинал находится по адресу http://www.interface.ru/home.asp?artId=20263