Работа со строками в Delphi

Строковый тип данных — наиболее широко используемый тип данных в стандартных приложениях. При работе со строковыми значениями можно применять один из доступных строковых типов или массив символов. Delphi позволяет использовать операцию присваивания для присвоения строкового значения массиву символов. 

var
s: array[0..255of Char;
begin
s := 'Hello1; end.
 

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

Delphi по-прежнему поддерживает старый строковый тип языка Pascal, но в Delphi этот строковый тип называется ShortString. Память для типа ShortString, как и память для массива символов, резервируется статически, и этот тип всегда использует 256 байтов стековой памяти. Тип ShortString может содержать не более 255 символов. Первый символ, индекс которого равен 0. содержит длину строки — действительное количество символов в типе ShortString.

В следующем примере отображается длина и объем памяти, занимаемой переменной типа ShortString. Для выяснения количества байтов, занимаемых переменной, можно использовать функцию SizeOf.

Листинг 6.11. Сведения о переменной типа ShortString


По многим причинам тип ShortString был заменен типом AnsiString. Использование множества коротких строковых значений ведет к бесполезной трате ценного объема памяти. С другой стороны, работа с действительно длинными строками невозможна, поскольку длина строки типа ShotrString ограничена 255 символами.
С целью решения проблемы бесполезной траты памяти Delphi позволяет явно указывать максимальную длину строки. Синтаксис объявления строки с явно определенной длиной выглядит следующим образом:
ИмяПеременной: string [Длина]; UserName: string[15];
Для объявления строки с явно указанной длиной используется зарезервированное слово string, которое обычно служит для объявления переменных типа AnsiString (длинная строка). При явном указании длины строки результирующей переменной будет переменная типа ShortString, которая занимает Длина + 1 байт. Этот дополнительный байт — первый байт, содержащий длину строки. В данном случае переменная UserName занимает 16. а не 256 байтов памяти.
По умолчанию зарезервированное слово string представляет тип данных AnsiString. который может содержать до 2 Гбайт символов. Значение зарезервированного слова string можно изменять директивами компилятора $Н и SLONGSTRINGS. Поскольку тип данных string предоставляет значительно больше возможностей, чем тип ShortString, нет никакой необходимости изменять его поведение, определенное по умолчанию.
Основное различие между типами данных ShortString и string состоит в том. что память для строк динамически резервируется в куче. Это означает, что их размер может изменяться во время выполнения и что они занимают в памяти не больше места, чем требуется. Несмотря на то что память для строк резервируется динамически, при работе со строками можно не беспокоиться о резервировании и освобождении памяти, поскольку Delphi выполняет эти действия автоматически.
Еще одно важное преимущество типа данных string связано с тем, что для него ведется подсчет ссылок. При каждом присваивании строки типа ShortString другой строке типа ShortString компилятор копирует все 256 байт. В отличие от этого, при присваивании строки типа string другой строке типа string строка не копируется. После выполнения операции присваивания целевая строка лишь указывает на первый символ исходной строки, а значение счетчика ссылок исходной строки увеличивается на единицу.
Таким образом, в памяти хранится только одна копия строкового значения, но ее используют несколько переменных. При присваивании одной строки другой независимо от размера строки выполняется копирование только 4 байт памяти. В следующем примере показаны две переменные, которые используют одно и то же значение.

Delphi создает действительную копию строки только при изменении ее содержимого. При изменении ее содержимого строка становится "автономной" и счетчик ссылок исходной строки уменьшается. Когда значение этого счетчика становится равным О,Delphi автоматически освобождает память, занятую строкой. 

Delphi предлагает большое число вспомогательных процедур и функций, которые работают со строками. В этой главе рассмотрены только те из них, которые применяются наиболее часто. К ним относятся:

  • Функция Pos (Subs tr: string; S: string):  Integer;
  • Функция Copy (S;  Index, Count:  Integer) : string;
  • Функция Length (S) :  Integer;
  • Функция IntToStr(Value: Integer): string; overload;
  • Функция StrToInt (const S: string):  Integer;
  • Процедура Delete(var S: string;  Index, Count:Integer);
  • Процедура Insert(Source: string; var S: string; Index: Integer);
  • Процедура Val (S; var V; var Code:  Integer);
  • Процедура Str(X [: Width  [: Decimals ]]; var S) ; 

Поиск в строке можно реализовать вручную или с помощью функции Pos. Эта функция возвращает значение 0, если подстроку не удается найти в строке. Пример использования функции Pos для определения того, содержит ли строка одно слово или больше, приведен в следующем листинге.

Листинг 6.12. Поиск в строке с помощью функции Pos


Если в строке необходимо выполнить поиск только одного символа, можно реализовать нестандартную функцию Pos. Следующая функция возвращает индекс символа в строке, если он найден, или О. если символ отсутствует.
Листинг 6.13. Поиск символа вручную 

Процедура Insert принимает три параметра. Первый из них — строковое значение, которое должно быть вставлено в другую строку, второй — строка назначения, а последний — индекс позиции вставки строки.

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

Листинг 6.14. Использование процедуры Insertprogram


В данном случае нельзя использовать цикл for. поскольку длина строки изменяется внутри цикла. Если использовать цикл for. все пробелы будут вставлены перед или после первой запятой. Это происходит потому, что длина строки считы-вается только в начале цикла for. Поскольку оба цикла — и repeat-until, и while— всегда повторно вычисляют условие, можете попробовать написать версию этого примера с применением цикла while.

Процедура Delete позволяет удалять из строки определенное количество символов. Она принимает три параметра: параметр переменной изменяемой строки, индекс позиции, с которой должно начинаться удаление, и количество удаляемых символов.В следующем примере процедура Delete применяется для удаления из строки всех пробелов. Процедура RemoveSpaces вызывает процедуру Delete до тех пор, пока в исходной строке остаются какие-либо пробелы. Параметр должен быть параметром-переменной, поскольку это единственный тип параметра, который позволяет изменять исходную переменную.
Листинг 6.15. Использование процедуры Delete

Функция Copy принимает три параметра. Первый из них — исходная строка, второй — индекс позиции, с которой должно начинаться копирование, а последний параметр определяет количество копируемых символов

 

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

Листинг 6.16. Использование функции Сору


Эта версия функции GetFilePath работает только в операционной системе Windows, поскольку она выполняет поиск только символа обратной косой черты. В операционной системе Linux она не работает, так как в Linux разделителем каталогов служит символ косой черты.
Если доподлинно известно, что функция или процедура предназначена для работы на конкретной платформе, для придания ей действительно профессионального вида ее следует пометить директивой plat form.
function GetFilePath(const AFileName: string): string; platform;
Когда процедура или функция помечена директивой platform, компилятор всегда будет выводить предупреждение о том, что данная процедура или функция предназначена для работы на конкретной платформе.
В данном случае функцию легко сделать не зависящей от платформы. Модуль SysUtils содержит глобальную константу, которая хранит соответствующие символы-разделители для каждой из платформ.
Чтобы сделать функцию GetFilePath не зависящей от платформы, достаточно изменить оператор if-then в цикле следующим образом:

Возможно, наиболее часто используется преобразование между строковыми и целыми типами данных. Общепринятый способ выполнения этих преобразований состоит в применении функций IntToStr и StrToInt, которые определены в модуле SysUtils. Эти функции просты в использовании и работают действительно быстро.

 

Если вы стремитесь к созданию действительно небольшого приложения, то. вероятно, удалите модуль SysUtils из списка uses. В этом случае можно использовать процедуры Str и Val. которые объявлены в модуле System.

Процедура Val принимает три параметра: строковое значение, которое необходимо преобразовать в целое, целевую целочисленную переменную и параметр кода ошибки. Если процедуре Val не удастся преобразовать строку в целочисленное значение, переменная, переданная ей в качестве последнего параметра, будет содержать индекс символа, который не может быть преобразован.

dle

Помоги проекту! Расскажи друзьям об этом сайте: