четверг, 28 апреля 2011 г.

Строковые типы

Перевод из справочной системы Delphi

О строковых типах

Строка представляет собой последовательность символов. Delphi поддерживает следующие предопределенные строковые типы:

ТипМаксимальная длинаТребует памятиИспользуется для
ShortString255 символовОт 2 до 256 байтОбратной совместимости
AnsiString~2^31 символовОт 4 байт до 2GB8-битные (ANSI) символы, DBCS ANSI, MBCS ANSI, символы Unicode и т.д.
UnicodeString~2^30 символовОт 4 байт до 2GBСимволы Unicode, 8-битные (ANSI) символы, многопользовательские серверы и приложения с поддержкой нескольких языков
WideString~2^30 символовОт 4 байт до 2GBСимволы Unicode; многопользовательские серверы и приложения с поддержкой нескольких языков. Использование UnicodeString обычно более предпочтительно, чем использование WideString (кроме приложений COM).

Замечание: Строковый тип по умолчанию - UnicodeString. Тип WideString предназначен для совместимости с типом COM BSTR. В общем случае следует использовать UnicodeString для не-COM приложений. Для большей части задач тип UnicodeString является предпочтительным. Тип string является псевдонимом для типа UnicodeString.

Строковые типы могут смешиваться при присваивании и построении выражений, - компилятор автоматически производит необходимые преобразования. Однако строки, передаваемые по ссылке в функцию или процедуру (как параметры var и out) должны соответствовать по типу формальным параметрам. Строки могут быть явным образом преобразованы в строки других типов. Тем не менее, преобразование мультибайтовой строки в однобайтовую строку может привести к потере данных.

Есть несколько особых строковых типов, о которых следует упомянуть:

  • Тип AnsiString зависит от кодовой страницы и объявлен следующим образом
    Type mystring = AnsiString(CODEPAGE). 
    Это тип AnsiString, который имеет возможность обрабатывать свои внутренние данные в определенной кодовой странице.
  • Тип RawByteString это тип AnsiString($FFFF). RawByteString позволяет передавать строковые данные любой кодовой страницы без выполнения преобразований кодовой страницы. RawByteString должен использоваться только как параметр const, параметр-значение или значение, возвращаемое функцией. Никогда не следует передавать его по ссылке и создавать экземпляры этого типа путем объявления переменных.
  • UTF8String представляет собой строку, закодированную при помощи UTF-8 (переменное количество байт Unicode). Это тип зависит от кодовой страницы и представляет собой AnsiString с кодовой страницой UTF-8.

Зарезервированное слово string действует как общий идентификатор строковых типов. Например:

var S: string;

создает переменную S, которая содержит строку. На платформе Win32, компилятор интерпретирует тип string (когда он встречается в коде без числа в квадратных скобках) как UnicodeString.

На платформе Win32, вы можете использовать директиву {$H-} для переключения от типа string к ShortString. Потенциально это полезный прием для работы со старым 16-битным кодом Delphi или Turbo Pascal в ваших новых программах.

Следует учесть, что ключевое слово string так же используется для объявления типов ShortString с заранее определенной длинной.

Сравнение строк выполняется путем определения порядковых номеров элементов стоящих на соответствующих позициях. При сравнении строк неравной длины, каждый символ в более длинной строке при отсутствии соответствующего символа в более короткой строке считается за большее значение. Например, 'AB' больше, чем 'A'; то есть выражение 'AB' > 'A' возвращает значение True. Строки с нулевой длинной представляют собой наименьшие значения при сравнении.

Вы можете индексировать строковую переменную так, как будто вы обрабатываете массив. Если S – это строка типа, отличного от UnicodeString, а i – это целочисленное выражение, то S[i] представляет i-ый байт в S, который может не быть i-ым символом или вообще не быть целым символом в том случае, если вы вы работаете с мультибайтовой строкой (MBCS). Таким же образом индексирование переменной типа UnicodeString может не обеспечить доступ к конкретному символу. Если строка содержит символы в Базовом Многоязыковом Плане (Basic Multilingual Plane (BMP)), все символы являются двухбайтовыми, а индексирование обеспечит доступ к символам строки. Однако, если некоторые символы не присутствуют в BMP, индексируемый элемент может не оказаться суррогатной парой – целым символом.

Стандартная функция Length возвращает количество элементов в строке. Как было указано, количество элементов не обязательно равно количеству символов. Процедура SetLength устанавливает длину строки. Следует учесть, что функция SizeOf возвращает количество байт, необходимых для представления переменной или типа, и только для типов ShortString это число будет равно количеству символов. Для всех остальных типов строк функция SizeOf возвращает количество байт в указателе (поскольку эти типы являются указателями).

Для типов ShortString или AnsiString S[i] является значением типа AnsiChar. Для WideString S[i] – это значение типа WideChar. Для однобайтовых (Западных) региональных стандартов (locale) MyString[2]:= 'A' присваивает значение 'A' второму символу в MyString. В следующем примере используется стандартная функция UpCase для преобразования значения MyString в заглавные буквы:

var I: Integer;
begin
  I := Length(MyString);
  while I > 0 do
  begin
    MyString[I] := UpCase(MyString[I]);
    I := I - 1;
  end;
end;

Будьте внимательны индексируя строки таким образом, поскольу перезапись конца строки может привести к ошибкам доступа (access violation). Кроме того, следует избегать передачи индексов строк как параметров var, поскольку это снижает эффективность кода.

Вы можете присвоить переменной значение строковой константы или любого другого выражения, возвращающего строку. Длина строки динамически изменяется при выполнении присваивания. Примеры:

MyString := 'Hello world!';
MyString := 'Hello' + 'world';
MyString := MyString + '!';
MyString := ' '; { space }
MyString := '';  { empty string }

Короткие строки

Переменные типа ShortString могут хранить от 0 до 255 однобайтовых символов. Поскольку длина ShortString может динамически изменяться, в памяти статически выделяется 256 байт, при этом первый байт содержит длину строки, а оставшиеся 255 доступны для хранения символов. Если переменная S имеет тип ShortString, то Ord(S[0]), как и Length(S), возвращаяет длину S; присваивание значения S[0], как и вызов SetLength, изменяет длину S. ShortString поддерживается только для обратной совместимости.

Язык Delphi поддерживает короткострочные типы - фактически, подтипы типа ShortString – в которых максимальная длина строки может быть от 0 до 255 символов. Количество символов определяется по числу, указываемому в квадратных скобках и идущему после зарезервированного слова string. Например:

var MyString: string[100];

создает переменную с именем MyString, максимальная длина строки у которой – 100 символов. Это эквивалентно объявлениям:

type CString = string[100];
var MyString: CString;

Переменные, объявленные таким образом, занимают в памяти столько места, сколько в точности требуется для хранения их значений. То есть указанная максимальная длина строки плюс один байт. В нашем примере MyString использует 101 байт по сравнению с 256 байтами для переменной предопределенного типа ShortString.

Если при присваивании значения переменной типа ShortString, длина значения превышает максимальную длину строки для типа, - значение обрезается.

Стандартные функции High и Low работают с идентификаторами короткострочных типов и переменными этих типов. High возвращает максимальную длину строки, а Low возвращает ноль.


Тип AnsiString

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

Переменная типа AnsiString – это структура, содержащая строковую информацию. Когда переменная пуста (то есть содержит строку нулевой длины), указатель имеет значение nil и строка не использует никакого дополнительной памяти для хранения. Когда переменная непуста, она указатель указывает на динамически выделенный блок памяти, содержащий строковое значение. Эта память динамически выделена в куче, но управление ею происходит полностью автоматически и не требует дополнительного пользовательского кода. Структура типа AnsiString содержит 32-битный индикатор, 32-битный счетчик ссылок, 16-битный индикатор для количества байт на символ и 16 бит на кодовую страницу.

Тип AnsiString представляет собой однобайтовую строку. С однобайтовыми наборами символов (single-byte character set (SBCS)) каждый байт в строке представляет собой один символ. В мультибайтовых наборах символов (multibyte character set (MBCS)) элементы являются однобайтовыми, при этом одни символы представляются одним байтом, а другие – более чем одним байтом. Мультибайтовые наборы символов (в особенности двухбайтовые (double-byte character sets (DBCS))) широко используются для азиатских языков. Строка типа AnsiString может содержать символы MBCS.

Доступ к символам AnsiString по индексу начинается с единицы. Индексирование многобайтовых строк ненадежно, поскольку S[i], представляет i-ый байт (не обязательно i-ый символ) в S. Тем не менее, стандартные функции для работы с AnsiString имеют мультибайтовые компоненты, которые так же реализуют сортировку символов по региональному стандарту.(Имена мультибайтовых функций обычно начинаются с префикса Ansi, например, мультибайтовая версия StrPos - AnsiStrPos.) Поддержка мультибайтовых символов зависит от операционной системы и базируется на локальных настройках.

Поскольку переменные типа AnsiString имеют указатели, две или более переменных может ссылаться на одно и то же значение без потребления дополнительной памяти. Компилятор функционирует таким образом для экономии ресурсов и более быстрого выполнения инструкций присваивания. При разрушении значения переменной или при выполнении присваивания, счетчик ссылок для предыдущего значения переменной уменьшается, а счетчик ссылок для нового значения – увеличивается (если таковое существует) – увеличивается. Когда счетчик ссылок для строки становится равным нолю, память высвобождается. Этот процесс называется подсчетом ссылок. Когда индексирование используется для изменения значения единичного символа в строке, производится копирование строки (но только в том случае, когда счетчик ссылок больше единицы). Это называется семантикой копирования при записи.


Тип UnicodeString

Тип UnicodeString представляет собой динамически изменяемые строки Unicode, максимальная длина которых ограничивается только доступной памятью.

В наборе символов Unicode каждый символ представлен одним или несколькими байтами. Unicode имеет несколько форматов преобразования (Unicode Transformation Formats) которые используют разные, но эквивалентные друг другу кодировки символов, которые могут быть легко преобразованы друг в друга.

  • В UTF-8, например, символы могут занимать от 1 до 4 байт. В UTF-8 первые 128 символов Unicode предназначены для символов US-ASCII.
  • UTF-16 – еще одна широко используемая кодировка Unicode, в которой символы занимают 2 или 4 байта.Большая часть мировых символов входит в Basic Multilingual Plane и может быть представлена 2 байтами. Остальные символы, которые требуют 2 байта, известны как суррогатные пары (surrogate pairs).
  • В UTF-32 для представления каждого символа требуется 4 байта.

Платформа Win32 поддерживает как однобайтовые и мультибайтовые наборы символов, так и Unicode. Операционная система Windows поддерживает UTF-16.

Тип UnicodeString имеет точно такую же структуру, как и AnsiString. Данные UnicodeString кодируются в UTF-16.

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

Экземпляры UnicodeString могут индексировать символы. Индексирование начинается с 1, так же как и для AnsiString.

Тип UnicodeString совместим по присваиванию с остальными строковыми типами. Тем не менее, при присваивание между AnsiString и UnicodeString выполняется соответствующие преобразования. Следует учесть, что присваивание значения типа UnicodeString переменной типа AnsiString не рекомендовано и может повлечь за собой потерю данных.

Delphi так же поддерживает символы и строки Unicode для типов WideChar, PWideChar и WideString.


Тип WideString

Тип WideString представляет собой динамически изменяемую строку, состоящую из 16-битных символов Unicode. В некотором смысле он схож с AnsiString. На платформе Win32, WideString совместим с типом COM BSTR.

WideString подходит для использования в приложениях COM. Тем не менее, WideString не имеет счетчиков ссылок, что для остальных типов приложений тип UnicodeString является более гибким и эффективным.

Индексирование WideString ненадежно, поскольку S[i] представляет iый элемент (не обязательно iый символ) в S.

Для Delphi типы Char и PChar аналогичны типам WideChar и PWideChar, соответственно.


Работа со строками, завершающимися нулевым символом

Множество языков программирования, включая C и C++, не имеют специальных типов для работы со строками. Эти языки и среды, которые разработаны с их помощью, работают со строками, заканчивающимися нулевым символом. Строки, завершающиеся нулевым символом – это массивы символов (индексация начинается с нулевого символа), последний элемент в которых - NUL (#0). Поскольку массив не имеет индикатора длины, первый символ NUL помечает конец строки. Вы можете воспользоваться конструкциями Delphi и специальными подпрограммы в модуле SysUtils для работы с такими строками в тех случаях, когда вы хотите работать с системами, которые их используют.

Следующие объявления типов могут быть использованы для хранения строк, завершающихся нулевым символом:

type
  TIdentifier = array[0..15] of Char;
  TFileName = array[0..259] of Char;
  TMemoText = array[0..1023] of WideChar;

При включенной директиве расширенного синтаксиса ({$X+}) вы можете присваивать значения строковых констант статическим символьным массивам с индексацией от нуля. (Динамические массивы для этой цели не подойдут.) Если вы инициализируете константу-массив, содержащую строку, которая короче, чем объявленная длина массива, оставшиеся символы устанавливаются в #0.


Использование указателей, массивов и строковых констант

Для работы со строками, завершающихся нулевым символом, часто бывает необходимо использовать указатели. Строковые константы совместимы по присваиванию с типами PChar и PWideChar, которые представляются указателями на массивы значений Char и WideChar, завершающиеся нулевым символом. Например:

var P: PChar;
  ...
P := 'Hello world!'

P указывает на область памяти, которая содержит завершающуюся нулевым символом копию 'Hello world!' Это эквивалентно:

const TempString: array[0..12] of Char = 'Hello world!';
var P: PChar;
   ...
P := @TempString[0];

Вы можете также передавать строковые константы в любую функцию, принимающую параметры-значения или параметры-константы типа PChar или PWideChar – например, StrUpper('Hello world!'). Как и при присваивании типу PChar, компилятор генерирует копию строки, оканчивающуюся нулевым символом, и передает функции указатель на эту копию. Наконец, вы можете инициализировать константы (отдельно взятые или в составе структурированных типов) типа PChar или PWideChar строковыми литералами. Примеры:

const
  Message: PChar = 'Program terminated';
  Prompt: PChar = 'Enter values: ';
  Digits: array[0..9] of PChar =
    ('Zero', 'One', 'Two', 'Three', 'Four', 'Five',
     'Six', 'Seven', 'Eight', 'Nine');

Индексируемые от ноля символьные массивы совместимы с типами PChar и PWideChar. Когда вы используете массив символов вместо указателя, компилятор преобразует массив в константу указательного типа, значение которой соответствует адресу первого элемента массива. Например:

var
  MyArray: array[0..32] of Char;
  MyPointer: PChar;
begin
  MyArray := 'Hello';
  MyPointer := MyArray;
  SomeProcedure(MyArray);
  SomeProcedure(MyPointer);
end;

Этот код дважды вызывает SomeProcedure, передавая ей одно и то же значение.

Символьный указатель может быть проиндексирован как массив. В предыдущем примере MyPointer[0] возвращает H. Индекс указывает на смещение, добавляемое к указателю перед получением значения. (Для переменных типа PWideChar индекс автоматически умножается на два.) Таким образом, если P – это символьный указатель, то P[0] эквивалентно P^ и определяет первый символ в массиве, P[1] определяет второй символ и так далее. P[-1] определяет 'символ' находящийся слева от P[0]. Компилятор не производит проверки диапазона на таких индексах.

Функция StrUpper иллюстрирует индексирование указателей для проходу по строке, заканчивающейся нулевым символом:

function StrUpper
  (Dest, Source: PChar; MaxLen: Integer): PChar;
var
  I: Integer;
begin
  I := 0;
  while (I < MaxLen) and (Source[I] <> #0) do
  begin
    Dest[I] := UpCase(Source[I]);
    Inc(I);
  end;
  Dest[I] := #0;
  Result := Dest;
end;

Смешивание строк Delphi и строк, оканчивающихся нулевым символом

Вы можете перемешивать строки (значения типов AnsiString и UnicodeString) и строки, оканчивающиеся нулевым символом (значения типа PChar) в выражениях и инструкциях присваивания, а так же можете передавать значения типа PChar в функции или процедуры, принимающие строковые параметры. Присваивание S := P, где S – строковая переменная, а P – выражение типа PChar, копирует строку, оканчивающуюся нулевым символом в обычную строку.

В двоичной операции, если один операнд является строкой, а второй – значением типа PChar, операнд типа PChar преобразуется в UnicodeString.

Вы можете преобразовывать значение PChar в UnicodeString. Это может быть полезно, если вы хотите выполнить строковую операцию с двумя значениями PChar. Например:

S := string(P1) + string(P2);

Вы можете также преобразовать строку типа UnicodeString или AnsiString в строку, оканчивающуюся на нулевой символ. При этом будут действовать следующие правила:

  • Если S – это UnicodeString, PChar(S) преобразует S в строку, оканчивающуюся нулевым символом и возвращает указатель на первый символ в S. Такие преобразования используются для Windows API. Например, если Str1 и Str2 – это UnicodeString, вы можете вызвать функцию Win32 API MessageBox следующим образом:
    MessageBox(0, PChar(Str1), PChar(Str2), MB_OK);
    Используйте PAnsiChar(S) в том случае, когда S – это строка типа AnsiString.
  • Вы также можете использовать Pointer(S) для преобразования строки в нетипизированный указатель. Но, если S пуста, такое преобразование вернет значение nil.
  • PChar(S) всегда возвращает указатель на блок памяти; если S пуста, возвращается указатель на символ #0.
  • Когда вы преобразуете значение переменной типа UnicodeString или AnsiString в указатель, он действует до тех пор, пока переменной не присваивается новое значение или не выходит из области видимости. Если вы преобразуете любое другое строковое выражение в указатель, он действует только внутри инструкции, в которой выполняется преобразование.
  • Когда вы преобразуете выражение типа UnicodeString или AnsiString в указатель, он должен рассматриваться как доступный только для чтения.

Аналогичные правила действуют при смешивании значений типов WideString и PWideChar.

Комментариев нет:

Отправить комментарий