AnsiReplaceStr — Функция Delphi

Содержание

AnsiReplaceStr — Функция Delphi

Некоторые обычные операции со строками и динамическими массивами можно делать в 100 раз быстрее.

ReplaceStr

Функции замены подстроки AnsiReplaceStr и AnsiReplaceText работают довольно медленно для текстов размером сотни килобайт c тысячами замен подстроки. Узкое место оказалась в медленном сложении строк типа
LongText := LongText + ShortText

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

Сначала создадим отдельный класс для хранения строки.

TW > private
FText: WideString;
LenText: Integer; //index of the last char
CurrentLenText: Integer; //actual length от FText
SpareLen: Integer;
function GetText: WideString;
procedure SetText(const Text: WideString);
public
procedure Append(C: WideString);
property Text: WideString read GetText write SetText;
property Length:Integer read LenText;
end;

function TWideString.GetText: WideString;
begin
CurrentLenText := LenText;
SetLength(FText, CurrentLenText);
GetText := FText;
end;

procedure TWideString.SetText(const Text: WideString);
begin
FText := Text;
LenText := Length(Text);
CurrentLenText := LenText;
end;

procedure TWideString.Append(C: WideString);
var i, LenC: integer;
begin
LenC := Length(C);
if LenText + LenC > CurrentLenText then
begin
SpareLen := max(SpareLen, CurrentLenText);
CurrentLenText := LenText + LenC + SpareLen;
SetLength(FText, CurrentLenText);
end;
for i := 1 to LenC do
begin
inc(LenText);
FText[LenText] := C[i];
end;
end;

Для поиска подстроки требуется функция PosEx , но в Delphi7 она неправильно работает со строками WideString . Поэтому используем функцию WidePosEx .

function WidePosEx(const SubStr, S: WideString; Offset: Integer): Integer;
var i, X, Len, LenSubStr, Res: Integer;
begin
if Offset = 1 then Res := Pos(SubStr, S) else
begin
i := Offset;
LenSubStr := Length(SubStr);
Len := Length(S) — LenSubStr + 1;
while i exit;
end;
end;
Inc(i);
end;
Res := 0;
end;
W > end;

Наконец, можно написать функцию замены подстроки.

function ReplaceStr(const Source, oldStr, newStr: WideString): WideString;
var PosOfOldStr, PosOfNextSearch, LenOldStr: integer; Res: TWideString;
begin
LenOldStr := Length(oldStr);
Res := TWideString.Create;
PosOfNextSearch := 1;
repeat
PosOfOldStr := WidePosEx(oldStr, Source, PosOfNextSearch);
if PosOfOldStr = 0 then break;
Res.Append(copy(Source, PosOfNextSearch, PosOfOldStr — PosOfNextSearch));
Res.Append(newStr);
PosOfNextSearch := PosOfOldStr + LenOldStr;
until PosOfOldStr = 0;
//till end of line
Res.Append(copy(Source, PosOfNextSearch, maxInt));
ReplaceStr := Res.Text;
Res.Destroy;
end;

Для тестирования я использовал похожий на xml текст размером 1Мб.

//usual making long text
t0 := Time;
for i := 1 to 50000 do txt := txt + ‘A1=»2345″ ‘;
dt0 := Time — t0;
//usual change of substring
t0 := Time;
txt := AnsiReplaceStr(txt, ’23’, ’67’);
dt1 := Time — t0;
//fast algorithm
t0 := Time;
txt := ReplaceStr(txt, ’45’, ’89’);
dt2 := Time — t0;

В этом примере на моём РС получилось
dt0 = 41 секунда
dt1 = 59 секунд
dt2 = 0.1 секунды

Теперь ясно, что самый обычный способ создания текста в цикле
txt := txt + ‘A1=»2345″ ‘
медленный, и его можно было бы ускорить, используя TWideString . Также можно ускорить функцию RemoveCrLfTabDSpace.

AnsiReplaceStr — Функция Delphi

Строки в Delphi состоят из одоного (тип ShortString ) или двух байтов (тип AnsiString, WideString ), содержащих указание количества символов в строке, и последовательности символов. Таким образом ShortString максимально может содержать до 255 символов и занимать память 2 байта ..256 байт, а AnsiString или WideString — максимально могут содержать примерно 2 x 10 30 символов и занимать память 4 байта .. 2 Гбайта.

В типе AnsiString символы кодируются в коде ANSI, а в типе WideString — в коде Unicode.

Общим типом является тип String , который может соответствовать как типу ShortString , так и типу AnsiString . Это определяется директивой компилятора $H . По умолчанию используется <$H+>, и тип String равен типу AnsiString .

Кроме того имеется тип PChar , представляющий так называемую строку с завершающим нулем. Строки с завершающим нулем не содержат байтов длины. В отличие от обычных строк они состоят из последовательности ненулевых символов, за которым следует символ NULL (#0). Никаких ограничений на длину строк с завершающим нулем не накладывается. Фактически он указывает на символ

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

где X — положительное число типа Integer , определяющее количество символов в строке, не считая завершающего символа с кодом 0. В отличие от типа String , символ с индексом 0 здесь является первым символом строки, а последний символ с индексом X — завершающим символом с кодом 0. (см. Функции работы со строками с завершающим нулем)

Список литературы:

  1. Гофман В.Э., Хомоненко А.Д. Delphi 6. — СПб. БХВ-Петербург, 2002. — 1152 с.: ил.
  2. Турбо Паскаль 7.0 — К. Торгово-издательское бюро BHV, 1996 — 448 с.: ил.
  3. Delphi7 Help

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

Дана строка. Преобразовать ее, удалив каждый символ «*».

как возможно реализовать удаление символов в строке, без применения работы с txt файлами и выводом на memo или edit?

Добавлено через 41 секунду
то есть мы вводим предложение или просто набор букв в обычный edit

23.01.2012, 11:20

Работа со строками, заполнить компоненты строками из файла
Привет! Нужна помощь в заполнении формы В общем, есть форма отправки письма. У нее есть 2 функции.

Работа со строками
С помощью текстового редактора создать файл, содержащий текст, длина которого не превышает 1000.

работа со строками
помогите перевернуть слово в edit-е наоборот. школа — алокш

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

Работа со строками
Дан текст на русском языке. Подсчитать количество слов, начинающихся и заканчивающихся на одну и ту.

AnsiReplaceStr — Функция Delphi

Работа со строками Delphi позволяет извлечь из строки необходимую информацию и представить её в нужном виде. Система предоставляет весь спектр необходимых функций для работы со строками Delphi и преобразования строк Delphi в необходимые форматы:

  • числовой формат, целый и дробный с плавающей точкой;
  • формат времени, даты, даты-времени;
  • преобразование символов к верхнему или нижнему регистру;
  • сравнение строк, поиск в строке и копирование подстроки;
    и многие другие.

Непосредственно сами строки Delphi поддерживают единственную операцию, так называемую операцию конкатенации, то есть присоединения. Несмотря на «научное» название, операция конкатенации выполняет очень простую процедуру. С помощью операции конкатенации одна строка присоединяется к другой:

Результирующая строка S будет суммой двух слагаемых строк. Длина строки, то есть количество символов в строке, возвращается встроенной функцией

function Length(S: String): Integer;

Delphi работает со строками типа String, в котором длина строки записывается в начале строки, перед первым символом. Поэтому индекс первого символа в строке не 0, а 1. То есть, если:

S:=’Строка типа String’;

то S[1] — символ ‘С’, S[2] — символ ‘т’ , последний символ в строке — S[Length(S)], равный ‘g’.

Однако часто приходится иметь дело со строками типа PChar, которые использует операционая система Windows. В строках типа PChar длина строки определяется специальным символом конца строки — #0. Поэтому для использования функций Windows тип String необходимо предварительно переводить в тип PChar. Преобразование типа String в тип PChar выполняет функция

function PChar(S: String): PChar;

Для полноценной работы со строками Delphi используются следующие стандартные процедуры и функции:

Функции преобразования в числовой формат и обратно

Выполняя вычисления, используем для ввода данных и отображения результатов следующие функции, работающие со строками Delphi:

функция IntToStr(N: Integer): String
Преобразует целое число N в строку.
функция StrToInt(S: String): Integer
Преобразует строку S в целое число.
функция FloatToStr(X: Extended): String
Преобразует число с плавающей точкой X в строку.
функция StrToFloat(S: String): Extended
Преобразует строку S в число с плавающей точкой.

Процедуры и функции преобразования дат и времени

Сначала собственно функции, предоставляющие информацию о текущих дате и времени:

функция Now: TDateTime
Возвращает текущую дату и время.
функция Date: TDateTime
Возвращает текущую дату.
функция Time: TDateTime
Возвращает текущее время.

Далее, функции, работающие с составляющими даты и времени (год, месяц, число, день недели, часы, минуты, секунды и даже миллисекунды):

функция DayOfWeek(Date: TDateTime): Integer
Возвращает текущий номер дня недели: 1 — воскресенье, 7 — суббота.
процедура DecodeDate(Date: TDateTime; var Year, Month, Day: Word)
Разбивает дату Date на год — Year, месяц — Month и день — Day.
процедура DecodeTime(Time: TDateTime; var Hour, Min, Sec, MSec: Word)
Разбивает время Time на час — Hour, минуты — Min, секунды — Sec и миллисекунды — MSec.
функция EncodeDate(Year, Month, Day: Word): TDateTime
Объединяет год — Year, месяц — Month и день — Day в значение типа TDateTime.
функция EncodeTime(Hour, Min, Sec, MSec: Word): TDateTime
Объединяет час — Hour, минуты — Min, секунды — Sec и миллисекунды — MSec в значение типа TDateTime.

Наконец, собственно, функции, переводящие дату и время из формата TDateTime в строчный формат:

функция DateTimeToStr(DateTime: TDateTime): String
Преобразует дату и время DateTime в строку.
функция DateToStr(Date: TDateTime): String
Преобразует дату Date в строку.
функция TimeToStr(Time: TDateTime): String
Преобразует время Time в строку.

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

функция AnsiLowerCase(const S: String): String
Возвращает строку S, преобразованную к нижнему регистру.
функция AnsiUpperCase(const S: String): String
Возвращает строку S, преобразованную к верхнему регистру.
функция Length(const S: String): Integer
Возвращает количество символов в строке S.
функция Trim(const S: String): String
Удаляет из строки S начальные и завершающие пробелы и управляющие символы.
функция TrimLeft(const S: String): String
Удаляет из строки S начальные пробелы и управляющие символы.
функция TrimRight(const S: String): String
Удаляет из строки S завершающие пробелы и управляющие символы.

Следующие функции сравнивают две строки между собой:

функция AnsiCompareStr(const S1, S2: String): Integer
Сравнивает две строки S1 и S2 с учётом регистра символов.
Возвращает значение 0 если S1>S2
функция AnsiCompareText(const S1, S2: String): Integer
Сравнивает две строки S1 и S2 без учёта регистра символов.
Возвращает значение 0 если S1>S2

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

функция Pos(Substr: String; Str: String): Integer
Возвращает позицию (индекс) первого вхождения Substr в строке Str. Если Substr нет в Str, возвращает 0.
функция Insert(Source: String; var S: String; Index: Integer): Integer
Вставляет строку Source в строку S, начиная с номера символа, равного Index
процедура Delete(var S: String; Index, Count: Integer)
Удаляет из строки S подстроку, начинающуюся с номера символа, равного Index, и содержащую до Count символов.
функция StringReplace(const S, OldPattern, NewPattern: string; Flags: TReplaceFlags): String
Заменяет в строке S подстроку OldPattern на строку NewPattern с учётом флага TReplaceFlags. Для работы с этой функцией нужно создать переменную типа TReplaceFlags — это множество, и включить в него одно или оба значения из следующих:
rfReplaceAll — будут заменены все вхождения. Если это значение не будет включено во множество, то будет заменено только первое вхождение;
rfIgnoreCase — замена будет без учёта регистра символов. Если это значение не будет включено во множество, то замена будет чувствительна к регистру символов.

Наконец, функция копирования части строки:

функция Copy(S: String; Index, Count: Integer): String
Возвращает подстроку строки S, начиная с номера символа, равного Index и содержащую до Count символов.

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

function RealToStr(X: Real; Count: Integer): String; //Count — количество цифр после запятой
var S: String;
N: Integer;
begin
S:=FloatToStr(X); //после запятой — длинная последовательность цифр
//DecimalSeparator — константа, содержащая истинный разделитель целой и дробной частей числа N:=Pos(DecimalSeparator, S); //позиция запятой в строке
//вычисляем длину строки с нужным количеством знаков после запятой:
if N=0 //если в строке нет запятой — это целое число, и
then N:=Length(S) //тогда просто выводим это число
else N:=N+Count; //иначе вычисляем длину строки
Result:=Copy(S, 1, N); //копируем часть строки в результат
end;

Или вот, к примеру, текст модуля, обеспечивающего ввод в компонент Edit только чисел.

AnsiReplaceStr — Функция Delphi

function StringReplace ( const SourceString, OldPattern, NewPattern : string; Flags : TReplaceFlags ) : string;
Функция StringReplace заменяет первое или все вхождения подстроки OldPattern в SourceString строкой NewPattern в соответствии с настройками Flags.

function AnsiReplaceStr ( const HayStack, Needle, NewNeedle : string ) : string;
Функция AnsiReplaceStr заменяет все вхождения строки Needle в строку Haystack строкой NewNeedle.

AnsiReplaceStr Routine

Unit Edit

Description Edit

(Please provide a description in your own words. It is illegal to use the wording from the Delphi Help.)

Technical Comments Edit

(Known issues / Documentation clarifications / Things to be aware of)

Examples Edit

(Please provide links to articles/source code that show how to use this item.)

See Also Edit

(Please provide links to items specifically related to this item.)

User Comments/Tips Edit

(Please leave your name with your comment.)

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

Автор: Alex. Опубликовано в Программирование 31 Январь 2020 . просмотров: 23128

Для работы со строками в последних версиях Delphi разработчикам доступно большое количество функций, помимо которых ещё есть помощники для работы со строками, такие как TStringHelper, TStringBuilder и TRegEx. Во всём этом разнообразии бывает сложно найти нужную функцию. Я попытался разобраться, что есть в Delphi 10.1 Berlin для работы со строками и как этим всем пользоваться.

Итак, прежде чем начнём разбираться с функциями, замечу, что начиная с Delphi XE3, появился помощник TStringHelper, и теперь работать со строками можно как с записями. Т.е., если вы определили переменную со строкой (на картинке снизу – это myStr), то вы можете поставить точку и посмотреть, какие функции доступны. Это очень удобно.

Кстати аналогичные помощники появились и для работы с типами Single, Double и Extended: TSingleHelper, TDoubleHelper и TExtendedHelper.

Ну и конечно, помимо помощника TStringHelper, никуда не делся класс TStringBuilder, который используется для работы со строкой как с массивом, и который является полностью совместимым с .NET классом StringBuilder.

А для работы с текстовыми документами незаменимым окажется класс TRegEx, который является обёрткой над библиотекой PCRE, позволяющий использовать регулярные выражения для поиска, замены подстрок и расщепления текста на части.

Все приведённые в статье примеры сделаны с помощью Delphi 10.1 Berlin, поэтому в других версиях Delphi их работа не гарантируется.

Вот основные моменты, которые мы рассмотрим в статье:

Строки в Delphi

В последних версиях Delphi тип string, обозначающий строку, является псевдонимом встроенного типа System.UnicodeString. Т.е. когда вы объявляете переменную str: string, то автоматически вы объявляете переменную типа UnicodeString.

Кстати, на платформе Win32 вы можете использовать директиву « », которая превратит тип string в ShortString. С помощью этого способа вы можете использовать старый 16-битный код Delphi или Turbo Pascal в ваших проектах.

Обратите внимание, что кроме типа UnicodeString и ShortString в Delphi есть и другие типы строк, такие как AnsiString и WideString, однако дальше в статье мы будем рассматривать только работу со строками типа string.

Более глубокое изучение строк в Delphi вы можете начать с прочтения документации здесь.

Инициализация строк

Конечно, начнём мы с инициализации строк. Итак, рассмотрим объявление переменной с типом string.

В этой строчке кода мы объявляем переменную s с типом string, т.е., как было написано выше, по умолчанию с типом UnicodeString. Объявленные переменные с типом UnicodeString, в которые не присвоено значение, всегда гарантированно содержат строку нулевой длины. Чтобы теперь в переменной s была нужная нам строка, нужно просто присвоить переменной другое значение, например:

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

Изменение регистра

Для изменения регистра строк в Delphi есть функции LowerCase, UpperCase, TStringHelper.ToLower, TStringHelper.ToUpper, TStringHelper.ToLowerInvariant и TStringHelper.ToUpperInvariant. В нижний регистр строки меняют функции LowerCase, TStringHelper.ToLower и TStringHelper.ToLowerInvariant, остальные – в верхний. Обратите внимание, что функции LowerCase и UpperCase не работают с кириллицей. Функции TStringHelper.ToUpperInvariant и TStringHelper.ToLowerInvariant всегда работают независимо от текущей пользовательской локали. Вот примеры использования функций:

Конкатенация строк

Здесь конечно самый простой вариант – это использование оператора +. Но есть и другие варианты, например, функция Concat. А если вам нужно в цикле добавлять в конец одной строки большое количество других строк, то здесь пригодится метод Append класса TStringBuilder. Вот пример использования перечисленных способов:

Во всех четырёх переменных, после выполнения нашей программы, будет следующая строка: «Абвгдеёжзиклмнопрст». Четвёртый способ выглядит более громоздким, но у такого способа есть три преимущества. Во-первых, при большом количестве конкатенаций этот способ даст выигрыш по времени по сравнению с первыми тремя способами. Во-вторых, при создании объекта TStringBuilder вы сразу можете задать нужный размер массива для хранения строки, если он конечно известен. Это тоже даст выигрыш по времени. В-третьих, функция Append принимает на вход не только строки, но и другие типы, такие как Integer и Single, автоматически преобразуя их в строку.

Третий способ удобно использовать, если нужно сложить строки, находящиеся в массиве или списке. К тому же здесь первым параметром можно задать строку-разделитель, которая будет вставлена между строками, взятыми из массива. Вот пример, в котором формируется строка со списком городов, разделённых запятыми:

В результате выполнения этой функции получится строка «Москва, Санкт-Петербург, Севастополь».

Вставка подстроки в строку

Для того чтобы вставить внутрь строки подстроку вы можете использовать процедуру Insert или функцию TStringHelper.Insert. У класса TStringBuilder тоже есть аналогичная функция. Кстати, функция TStringBuilder.Insert, кроме строк умеет вставлять и другие типы, такие как Integer и Single, автоматически преобразуя их в строку. Вот пример использования:

Обратите внимание, в процедуре Insert нумерация символов начинается с 1, а в функциях TStringHelper.Insert и TStringBuilder.Insert – с 0. Все приведённые способы меняют строку, хранящуюся в переменной.

Удаление части строки

Допустим, вам нужно удалить из строки часть символов. Здесь нам помогут процедура Delete и функция TStringHelper.Remove. У класса TStringBuilder тоже есть функция Remove. Вот примеры использования:

Во всех трёх способах из строки «Абвгд» получится строка «Агд». Обратите внимание, что в процедуре Delete нумерация символов начинается с 1, а в функциях Remove – с 0.

Также интересно, что функция TStringHelper.Remove не трогает исходную строку. Вместо этого она возвращает новую строку с удалёнными символами. Именно поэтому мы присваиваем результат обратно в переменную. Процедура Delete работает по-другому: она меняет исходную строку.

Помимо приведённых здесь вариантов, для удаления части строки можно использовать функции замены подстроки, просто для этого искомая подстрока заменяется на пустую, например, StringReplace(str1, substr1, »).

Копирование части строки

Здесь идёт речь о том, что часть длиной строки нужно скопировать в новую строку или массив символов. Для этого в Delphi есть функции LeftStr, RightStr, Copy, TStringHelper.Substring и TStringHelper.CopyTo. А в классе TStringBuilder – только функция CopyTo. Есть также функция MidStr в юните System.StrUtils, которая работает аналогично функции Copy, поэтому в примере её не будет.

Первые два способа копируют часть строки слева (функция LeftStr) или справа (RightStr). Остальные четыре способа подходят, как для копирования части строки слева или справа, так и из середины.

В способах 3-6 из примера мы получим сроку «вгд» или массив [‘в’, ‘г’, ‘д’]. Обратите внимание, что в функциях Copy и MidStr нумерация символов начинается с 1, а во всех остальных с 0. Исходная строка или массив символов во всех четырёх способах не меняется.

Сравнение строк

Конечно, сравнивать строки можно с помощью операторов =, , >= и <>. Но кроме этого существуют ещё много функций: StrComp, StrIComp, StrLComp, StrLIComp, CompareStr, CompareText, TStringHelper.Compare, TStringHelper.CompareOrdinal, TStringHelper.CompareTo, TStringHelper.CompareText, SameStr, SameText, TStringHelper.Equals и TStringBuilder.Equals. Функции SameText, StrIComp, CompareText, TStringHelper.CompareText и TStringHelper.Compare умеют производить регистронезависимое сравнение строк, остальные функции и операторы — регистрозависимое.

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

Самая продвинутая здесь функция – это TStringHelper.Compare. С помощью неё можно сравнивать не только целые строки, но и части строк. Здесь можно настроить зависимость от регистра, включить игнорирование символов и знаков препинания или сравнение цифр как чисел и т.д.

Операторы, а также функции TStringHelper.Equals и TStringBuilder.Equals, в результате сравнения, отдадут вам True, если условие верно, и False, если условие не верно. Функции CompareStr, CompareText, TStringHelper.Compare, TStringHelper.CompareTo, TStringHelper.CompareOrdinal и TStringHelper.CompareText работают по-другому. Они сравнивают строки с точки зрения сортировки. Функции возвращают отрицательное число, если строка, указанная в первом параметре, сортируется до строки, указанной во втором параметре, положительное число — если первая строка сортируется после второй и 0 – если строки равны.

Функции SameStr, SameText, TStringHelper.Equals и TStringBuilder.Equals сравнивают строки на соответствие.

Итак, вот примеры использования вышеперечисленных функций и операторов:

Поиск подстроки в строке

Теперь давайте посмотрим, как можно найти подстроку (определённую последовательность символов) в строке. Здесь у вас есть большой выбор функций, которые возвращают либо индекс найденной подстроки, либо true или false в зависимости от того, найдена подстрока в строке или нет. Итак, давайте перечислим все функции для поиска подстроки:

В первую очередь – это функция Pos, которая ищет подстроку, начиная с указанного номера символа. Функция осуществляет регистрозависимый поиск. Здесь нумерация символов начинается с 1. Если подстрока найдена, то возвращается номер первого символа найденной подстроки, иначе – 0. Есть также функция PosEx (в юните System.StrUtils), которая работает абсолютно также. Вот пример использования функции Pos:

Аналогично функции Pos работают и функции IndexOf и LastIndexOf помощника TStringHelper. Они также осуществляют регистрозависимый поиск. Функция IndexOf ищет подстроку (или символ) с начала и до конца строки, а функция LasIndexOf – наоборот, т.е. с конца и до начала. Если подстрока найдена, то функции возвращают индекс первого символа найденной подстроки в строке. Здесь нумерация символов начинается с 0. Если подстрока не найдена, то функции возвращают -1. Также при поиске вы можете задать начало и интервал поиска. Вот примеры использования этих функций:

Теперь рассмотрим функции для проверки, есть ли подстрока в строке, и не важно, в каком месте. Для этого есть функции ContainsStr и ContainsText в юните System.StrUtils, а также функция Contains в помощнике TStringHelper.Contains. Функции ContainsStr и TStringHelper.Contains – регистрозависимые, а функция ContainsText – нет. Вот примеры использования этих функций:

Дополнительно есть функции проверяющие, наличие определённой подстроки в начале или в конце текста. Это функции StartsStr, StartsText, EndsStr и EndsText в юните System.StrUtils, а также функции StartsWith, EndsWith и EndsText у помощника TStringHelper. Функции StartsStr и EndsStr регистрозависимые, функции StartsText, EndsText и TStringHelper.EndsText регистронезависимые, а у функций TStringHelper.StartsWith и TStringHelper.EndsWith есть второй параметр для выбора режима поиска. Учтите, что регистронезависимый поиск в функции TStringHelper.StartsWith работает только с буквами латинского алфавита. По умолчанию поиск в функциях TStringHelper.StartsWith и TStringHelper.EndsWith регистрозависимый.

Обратите внимание, что регистронезависимый поиск в функциях StartsText, EndsText и TStringHelper.EndsText и TStringHelper.EndsWith ведётся для текущей локали. Т.е. если на компьютере будет установлена английская локаль, то регистронезависимый поиск по русскому тексту работать не будет.

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

И конечно самые продвинутые условия для поиска подстрок можно задавать при помощи регулярных выражений. Для этого есть функции TRegEx.Match и TRegEx.Matches. Вот несколько примеров использования этих функций:

Примеры и описание регулярных выражений смотрите на сайте библиотеки PCRE.

Поиск символов в строке

Случается, что нужно найти определённые символы в строке. Конечно, для этого вы можете воспользоваться функциями для поиска подстроки, о которых было написано выше, но есть и специальные функции, позволяющие найти первый попавшийся в строке символ из нескольких искомых. Это функции помощника TStringHelper: IndexOfAny, IndexOfAnyUnquoted и LastIndexOfAny. Функции IndexOfAny и IndexOfAnyUnquoted ищут, перебирая символы сначала до конца строки, а функция LastIndexOfAny – наоборот. Во всех функциях можно указать интервал поиска. Функция IndexOfAnyUnquoted умеет игнорировать символы, заключенные в кавычки, скобки и т.п. Вот пример использования этих функций:

Замена подстроки в строке

Для поиска и замены подстроки (или символа) в строке можно использовать функции StringReplace, ReplaceStr и ReplaceText, TStringHelper.Replace, TStringBuilder.Replace и TRegEx.Replace. Функции ReplaceStr и TStringBuilder.Replace – регистрозависимые, функция ReplaceText – регистронезависимая, в функциях StringReplace, TStringHelper.Replace и TRegEx.Replace зависимость от регистра настраивается флажком rfIgnoreCase. Функции TRegEx.Replace ищут подстроку, используя регулярные выражения. В функции TStringBuilder.Replace можно задать диапазон поиска подстроки. Вот примеры использования этих функций:

Обрезка пробелов и управляющих символов

Для такой часто встречающейся операции, как удаление пробелов и управляющих символов в начале и в конце строки, есть несколько функций: Trim, TrimLeft, TrimRight, TStringHelper.Trim, TStringHelper.TrimLeft и TStringHelper.TrimRight. При вызове функций TStringHelper.Trim, TStringHelper.TrimLeft и TStringHelper.TrimRight вы можете перечислить, какие символы нужно удалять. Вот пример использования этих функций:

Выравнивание текста за счёт установки пробелов

И напоследок ещё пара интересных функций, которые умеют дополнять строку пробелами или другими символами, пока она не станет нужной длины. Это функции TStringHelper.PadLeft и TStringHelper.PadRight. С помощью этих функций, например, для лучшего восприятия можно добавить пробелы в начало чисел, которые вы выдаёте столбиком в консоли или дополнить числа ведущими нулями. Вот пример использования этих функций:

Вместо заключения

Итак, в статье я постарался собрать все возможные функции Delphi, которые постоянно нужны при работе со строками. Надеюсь, вы найдёте в этой статье что-то новое и интересное для себя. Если я упустил что-то важное на ваш взгляд, просьба не держать это в себе, а написать об этом в комментариях.

Люди знающие Delphi помогите. В написаниии вот этого см внутри

procedure TForm1.Button1Click(Sender: TObject);
var i,n:integer;
Str,LeftSideStr,RightSideStr,NewStr:string;
begin
//заносим в Str текст
Str:=Edit1.Text;
//находим позицию точки
n:=pos(‘.’,Str);
//если точки нет, то
if n=0 then
begin
//подаем звуковой сигнал
MessageBeep($30);
//показываем сообщение
ShowMessage(‘В этой строке нет символа ‘+QuotedStr(‘.’));
//выходим их процедуры
exit;
end;

//вычисляем левую часть строки Str (до символа ‘.’)
LeftS > //вычисляем правую часть строки Str (начиная с символа ‘.’)
RightS >
//функция AnsiReplaceStr(AText, AFromText, AToText) заменяет все
//символы AFromText на AToText из текста AText
//и возвращает эту строку

//заносим в NewStr левую часть строки Str, но уже без запятых
NewStr:=AnsiReplaceStr(LeftSideStr,’,’,»);
//довавляем к NewStr правую часть строки Str, в которой
//все символы ‘+’ заменены на ‘5’
NewStr:=NewStr+AnsiReplaceStr(RightSideStr,’+’,’5′);

//заносим в Edit2.Text найденную строку
Edit2.Text:=NewStr;
end;

Сорри, я заменил символы ‘+’ на ‘5’. Думаю, принцип понятен.

Строковые типы в Delphi. Особенности реализации и использования

В этой статье будут освещены следующие вопросы:

  1. Какие строковые типы существуют в Delphi, и чем они отличаются друг от друга
  2. Преобразование строк из одного типа в другой
  3. Некоторые приемы использования строк типа AnsiString:
    1. Функции для работы со строками о которых многие часто забывают или вовсе не знают
    2. Передача строк в качестве параметров
    3. Использование строк в записях
    4. Запись в файл и чтение из файла
    5. Использование строк в качестве параметров и результатов функций размещенных в DLL.

Ну что, интересно? Тогда поехали.

Какие строковые типы существуют в Delphi, и чем они отличаются друг от друга?

В Delphi 1.0 существовал лишь единственный строковый тип String, полностью эквивалентный одноименному типу в Turbo Pascal и Borland Pascal. Однако, этот тип имеет существенные ограничения, о которых я расскажу позднее. Для обхода этих ограничений, в Delphi 2, разработчики из Borland устроили небольшую революцию. Теперь, начиная с Delphi 2, имеются три фундаментальных строковых типа: ShortString, AnsiString, и WideString. Кроме того, тип String теперь стал логическим. Т.е., в зависимости от настройки соответствующего режима компилятора (режим больших строк), он приравнивается либо к типу ShortString (для совместимости со старыми программами), либо к типу AnsiString (по умолчанию). Управлять режимом, можно используя директиву компиляции <$LONGSTRINGS ON/OFF>(короткая форма <$H+/->) или из окна настроек проекта – вкладка «Compiler» -> галочка «Huge strings». Если режим включен, то String приравнивается к AnsiString, иначе String приравнивается ShortString. Из этого правила есть исключение: если в определении типа String указан максимальный размер строки, например String[25], то, вне зависимости от режима компилятора, этот тип будет приравнен к ShortString соответствующего размера.

Поскольку, как вы узнаете в дальнейшем, типы ShortString и AnsiString имеют принципиальное отличие в реализации, то я вообще не рекомендую пользоваться логическим типом String без указания размера, если Вы, конечно, не пишете программ под Delphi 1. Если же Вы все-таки используете тип String, то я настоятельно рекомендую прямо в коде Вашего модуля указывать директиву компиляции, устанавливающую подразумеваемый Вами режим работы компилятора. Особенно если Вы используете особенности реализации соответствующего строкового типа. Если этого не сделать, то однажды, когда Ваш код попадет в руки другого программиста, не будет никакой гарантии того, что его компилятор будет настроен, так же как и Ваш.

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

Сразу же упомяну о различии между типами AnsiString и WideString. Эти типы имеют практически одинаковую реализацию, и отличаются лишь тем, что WideString используется для представления строк в кодировке UNICODE использующей 16-ти битное представление каждого символа (WideChar). Эта кодировка используется в тех случаях когда необходима возможность одновременного присутствия в одной строке символов из двух и более языков (помимо английского). Например, строк содержащих одновременно символы английского, русского и европейских языков. За эту возможность приходится платить – размер памяти, занимаемый такими строками в два раза больше размера, занимаемого обычными строками. Использование WideString встречается не часто, поэтому, я буду в основном рассказывать о строках типа AnsiString. Но, поскольку они имеют одинаковую реализацию, почти все сказанное относительно AnsiString будет действительно и для WideString, естественно с учетом разницы в размере каждого символа.

Тоже самое касается и разницы между pChar и pWideChar.

Строковый тип AnsiString, обычно используется для представления строк в кодировке ANSI, или других (например OEM) в которых для кодирования одного символа используется один байт (8 бит). Такой способ кодирования называется single-byte character set, или SBCS. Но, очень многие не знают о существовании еще одного способа кодирования многоязычных строк (помимо UNICODE) используемого в системах Windows и Linux. Этот способ называется multibyte character sets, или MBCS. При этом способе, некоторые символы представляются одним байтом, а некоторые, двумя и более. В отличие от UNICODE, строки, закодированные таким способом, требуют меньше памяти для своего хранения, но требуют более сложной обработки. Так вот, строковый тип AnsiString может использоваться для хранения таких строк. Я не буду подробно останавливаться на этом способе кодирования, поскольку он применяется крайне редко. Лично я, ни разу не встречал программ использующих данный способ кодирования.

Знатоки Delphi вероятно мне сразу напомнят еще и о типах pChar (pWideChar) и array [. ] of Char. Однако, я считаю, что это не совсем строковые типы, но я расскажу и о них, поскольку они очень часто используются в сочетании со строковыми типами.

Итак, приведу основные характеристики строковых типов:

Тип Максимальный размер строки Размер переменной Объем памяти, требуемый для хранения строки
String[n] где 0 0, поэтому то Delphi и не освобождает память, занятую строкой.

Еще, этот счётчик используется и для разрешения проблем, связанных со следующей ситуацией:

Здесь, как мы уже знаем, после выполнения оператора s2 := s1, обе переменные указывают на один и тот же экземпляр строки ‘abc123’. Однако, что же произойдёт когда выполниться оператор s2[1] := ‘X’? Казалось бы, в единственном имеющимся в нашем распоряжении экземпляре строки первая буква будет заменена на ‘X’. И как следствие, обе строки станут равными ‘Xbc123’. s1 то за что «страдает»? Но, к счастью это не так. Здесь на помощь Delphi вновь приходит счетчик ссылок. Delphi, при выполнении этого оператора понимает, что строка на которую указывает s2 будет изменена, а это может повлиять на других. Поэтому, перед изменением строки, проверяется ее счётчик ссылок. Обнаружив, что на нее ссылается более одной строковой переменной, делается следующее: создается копия этой строки со счётчиком ссылок равным 1, и адрес этой копии, присваивается s2; У исходного экземпляра строки, счетчик ссылок уменьшается на 1 – ведь s2 на неё теперь не ссылается. И лишь после этого, происходит изменение первой буквы, теперь уже собственного экземпляра строки. Т.е., по окончанию выполнения этого оператора, в памяти будут находиться две строки: ‘abc123’ и ‘Xbc123’. Причем, s1 будет ссылаться на первую, а s2 на вторую.

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

Казалось бы, при завершении работы процедуры, экземпляр строки ‘Вася’ должен быть уничтожен. Но в данном случае это не так. Ведь, при следующем входе в процедуру, для выполнения присваивания нужно будет вновь где-то взять строку ‘Вася’. Для этого, ещё при компиляции, Delphi размещает экземпляр строки ‘Вася’ в области констант программы, где её даже невозможно изменить, по крайней мере, простыми методами. Но как же при завершении процедуры определить что строка ‘Вася’ – константная строка, и ее нельзя уничтожать? Все очень просто. Для константных строк, счётчик ссылок устанавливается равным -1. Это значение, «выключает» нормальный алгоритм работы со «счётчиком ссылок». Он не увеличивается при присваивании, и не уменьшается при уничтожении переменной. Однако, при попытке изменения переменной (помните s2[1]:=’X’), значение счётчика равное -1 будет всегда считаться признаком того, что на строку ссылается более одной переменной (ведь он не равен 1). Поэтому, в такой ситуации всегда будет создаваться уникальный экземпляр строки, естественно, без декремента счётчика ссылок старой. Это защитит от изменений экземпляр строки-константы.

К сожалению, этот алгоритм срабатывает не всегда. Но об этом, мы поговорим позже, при рассмотрении вопросов преобразования строковых типов.

Где же Delphi хранит «счётчик ссылок»? Причем, для каждой строки свой! Естественно, вместе с самой строкой. Вот что представляет собой эта область памяти, хранящая экземпляр строки ‘abc’:

Байты с 1 по 4 Счётчик ссылок равный -1
Байты с 5 по 8 Длина строки равная 3
Байт 9 Символ ‘a’
Байт 10 Символ ‘b’
Байт 11 Символ ‘c’
Байт 12 Символ с кодом 0 (#0)

Для удобства работы с такой структурой, когда строковой переменной присваивается ссылка на эту строку, в переменную заносится адрес не начала этой структуры, а адрес её девятого байта. Т.е. адрес начала реальной строки (прямо как pChar). Для того, что бы приблизиться к реальной жизни, перепишем приведённую структуру:

Смещение Размер Значение Назначение
-8 4 -1 Счётчик ссылок
-4 4 3 Длина строки
1 ‘a’
1 1 ‘b’
2 1 ‘c’
3 1 #0

С полем по смещению -8, нам уже должно быть все ясно. Это значение, хранящееся в двойном слове (4 байта), тот самый счетчик, который позволяет оптимизировать хранение одинаковых строк. Значение этого счетчика имеет тип Integer, т.е. может быть отрицательным. На самом деле, используется лишь одно отрицательное значение – «-1», и положительные значения. 0 не используется.

Теперь, обратите внимание на поле, лежащее по смещению -4. Это, четырёхбайтовое значение длинны строки (почти как в ShortString). Думаю, Вы заметили, что размер памяти выделенной под эту строку не имеет избыточности. Т.е. компилятор выделяет под строку минимально необходимое число байт памяти. Это конечно хорошо, но, при попытке «нарастить» строку: s1 := s1 + ‘d’, компилятору, точнее библиотеке времени исполнения (RTL) придется перераспределить память. Ведь теперь строке требуется больше памяти, аж на целый байт. Для перераспределения памяти нужно знать текущий размер строки. Вероятно, именно для того, что бы не приходилось каждый раз сканировать строку, определяя её размер, разработчики Delphi и включили поле длины, строки в эту структуру. Длина строки, хранится как значение Integer, отсюда и ограничение на максимальный размер таких строк – 2 Гбайт. Надеюсь, мы не скоро упрёмся в это ограничение. Кстати, именно потому, что память под эти строки выделяется динамически, они и получили ещё одно свое название: динамические строки.

Осталось рассказать ещё о нескольких особенностях переменных AnsiString. Важнейшей особенностью значений этого типа является возможность приведения их к типу Pointer. Это впрочем, естественно, ведь в «душе» они и есть указатели, как бы они этого не скрывали. Например, если описаны переменные: s :AnsiString и p :Pointer. То выполнение оператора p := Pointer(s) приведет к тому, что переменная p станет указывать на экземпляр строки. Однако, при этом, очень важно знать: счетчик ссылок этой строки не будет увеличен. Но об этом, мы поговорим чуть позднее.

Поскольку, переменные этого типа реально являются указателями, то для них и реально такое значение как Nil – указатель в «никуда». Это значение в переменной типа AnsiString по смыслу приравнивается пустой строке. Более того, чтобы не тратить память и время на ведение счётчика ссылок, и поля размера строки всегда равного 0, при присваивании пустой строке переменной этого типа, реально, присваивается значение Nil. Это не очевидно, поскольку обычно не заметно, но как мы увидим позже, очень важная особенность.

Вот теперь, кажется, Вы знаете о строках все. Настала пора переходить к более интересной части статьи – как с этим всем жить?

Преобразование строк из одного типа в другой

Здесь, все как обычно, и просто и сложно.

Преобразование между «настоящими» строковыми типами String[n], ShortString, и AnsiString выполняются легко, и прозрачно. Никаких явных действий делать не надо, Delphi все сделает за Вас. Надо лишь понимать, что в маленькое большое не влезает. Например:

В результате выполнения этого кода, в переменной s3 окажется строка ‘abc’, а не ‘abcdef’. С преобразованием из pChar в String[n], ShortString, и AnsiString, тоже всё очень не плохо. Просто присваивайте, и все будет нормально.

Сложности начинаются тогда, когда мы начинаем преобразовывать «настоящие» строковые типы в pChar. Непосредственное присваивание переменным типа pChar значений строк не допускается компилятором. На оператор p := s где p имеет тип pChar, а s :AnsiString, компилятор выдаст сообщение: «Incompatible types: ‘String’ and ‘PChar'» — несовместимые типы ‘String’ и ‘PChar’. Чтобы избежать такой ошибки, надо применять явное приведение типа: p := pChar(s). Так рекомендуют разработчики Delphi. В общем, они правы. Но, если вспомнить, как хранятся динамические строки — с нулем в конце, как и pChar. А еще и то, что к AnsiString применимо преобразование в тип Pointer. Станет очевидным, что всего, возможно целых три способа преобразования строки в pChar:

Все они, синтаксически правильны. И кажется, что все три указателя (p1, p2 и p3) будут в результате иметь одно и то же значение. Но это не так. Всё зависит от того, что находится в s. Если быть более точным, равно ли значение s пустой строке, или нет:

Чтобы Вы понимали причину такого явления, я опишу, как Delphi выполняет каждое из этих преобразований. В начале напомню, что переменные AnsiString представляющие пустые строки, реально имеют значение Nil. Так вот:

Для выполнения преобразования pChar(s), компилятор генерит вызов специальной внутренней функции @LstrToPChar. Эта функция проверяет – если строковая переменная имеет значение Nil, то вместо него, она возвращает указатель на реально размещенную в памяти пустую строку. Т.е. pChar(s) никогда не вернет указатель равный Nil.

Тут все просто, такое преобразование просто возвращает содержимое строковой переменной. Т.е. если она при пустой строке содержит Nil, то и результатом преобразования будет Nil. Если же строка не пуста, то результатом будет адрес экземпляра строки.

Здесь, все совсем по другому. Перед выполнением такого преобразования, компилятор вставляет код, обеспечивающий ситуацию, когда указатель, хранящийся в s, будет единственным указателем на экземпляр строки в памяти. В нашем примере, если строка не пуста, то будет создана копия исходной строки. Вот ее-то адрес и будет возвращен как результат такого преобразования. Но, если строка пуста, то результатом будет Nil, как и во втором случае.

Теперь, интересно отметить, что если в приведенном примере, преобразование p3 := @(s[1]) выполнить первым, то при не пустой строке в s, все указатели (p1, p2, и p3), будут равны. И содержать они будут адрес «персонального» экземпляра строки.

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

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

Здесь, поскольку параметр передаётся по значению, при вызове будет создана локальная копия переменной (указателя) Msg. Об этом я ещё расскажу ниже. Эта переменная, при завершении процедуры будет уничтожаться, что приведёт к освобождению «персональной» копии экземпляра переданной и преобразованной строки.

Функции этой группы используются для сравнения строк. Результатом будет одно из значений:

>0 если S1 > S2
255 символов приходится платить.

Если же тебе достаточно и 255 символов, то используй ShortString, или String[n].

Есть еще одно, на мой взгляд, замечание. Если Вы обратили внимание на тип переменной Len в моем примере, то возможно у Вас возник вопрос: А почему LongInt, а не Integer? Жаль если у Вас вопрос не возник – либо вы все знаете, либо ничего :). Для остальных поясню: дело в том, что тип LongInt фундаментальный тип, размер которого (4 байта) не будет меняться в последующих версиях Delphi. А тип Integer, это универсальный тип, размерность которого может меняться от версии к версии. Например, для 64-разрядных компьютеров он наверняка «вырастет» до 8-ми байт (64 бита). Лично мне, хочется, что бы файлы данных записанные моей старой версией программы могли быть нормально прочитаны более поздними версиями, возможно скомпилированными уже под 64-разрядной OS.

Использование строк в записях

Проблема возникает тогда, когда одно поле (или несколько полей) имеют тип динамической строки. В этом случае, часто возникает проблема схожая с проблемой записи динамической строки в файл – не все данные лежат в записи, динамические строки представлены в ней лишь указателями. Решается проблема также как и с записью строк в файл. Жаль только что тогда нельзя будет оперировать (записать/прочитать) целиком всей записью. Строки придется обрабатывать особо. Можно сделать, например, так:

Обратите внимание на то, что перед записью в поток я делаю так, что бы в поле f3 попал указатель Nil. Если этого не сделать, то в поток попадет адрес текущего экземпляра динамической строки. При чтении, он будет прочитан в поле f3. Т.е. поле f3 станет указывать на какое-то место в памяти. При выполнении SetLength, поскольку Delphi сочтет что текущее значение f3 лежит по указанному адресу, будет попытка интерпретировать лежащую там информацию как динамическую строку. Если же в поток записать Nil, то SetLength, никуда лезть не будет – экземпляра-то нет.

Использование строк в качестве параметров и результатов функций размещенных в DLL.

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

Общий смысл этого эпоса в том, что если Ваша Dll экспортирует хотя бы одну процедуру или функцию с типом параметра соответствующим любой динамической строке (AnsiString например), или функцию, возвращающую результат такого типа. Вы должны обязательно и в Dll, и в использующей ее программе, первым модулем в списке импорта (uses) указать модуль ShareMem. И как следствие, поставлять со своей программой и Dll еще одну стандартную библиотеку BORLNDMM.DLL.

Вы не задумывались над вопросами: «Зачем все эти сложности?»; «Что будет если этого не сделать?» и «Можно ли этого избежать?»; «Если да, то как?» Если не задумывались, то самое время сделать это.

Попробуем разобраться что будет происходить с экземплярами динамических строк в следующем примере:

Сначала, при выполнении процедуры X, функция IntToStr(100) создаст экземпляр динамической строки ‘100’, и ее адрес будет помещен в переменную Str. Затем, адрес этой переменной будет передан процедуре Y. В ней, при выполнении оператора s := s+’$’, будет создан экземпляр новый строки ‘100$’, Экземпляр старой строки ‘100’ станет не нужным и память, выделенная для него при создании, будет освобождена. Кроме того, при завершении процедуры X, будет освобождена и память, выделенная для строки ‘100$’, так как перестанет существовать единственная ссылка на нее — переменная Str.

Всё вроде бы хорошо. Но до тех пор, пока обе процедуры располагаются в одном исполняемом модуле (EXE-файле). Если например поместить процедуру Y в Dll, а процедуру X оставить в EXE, то будет беда.

Дело в том, что выделением и освобождением памяти для экземпляров динамических строк занимается внутренний менеджер памяти Delphi-приложения. Использовать стандартный менеджер Windows очень накладно. Он слишком универсален, и потому медленный, а строки очень часто требуют перераспределения памяти. Вот разработчики Delphi и создали свой. Он ведет списки распределенной и свободной памяти своего приложения. Так вот, вся беда в том, что Dll будет использоваться свой менеджер памяти, а EXE свой. Друг о друге они ничего не знают. Поэтому, попытка освобождения блока памяти выделенного не своим менеджером приведёт к серьезному нарушению в его работе. Причем, это нарушение может проявиться далеко не сразу, и довольно необычным образом.

В нашем случае, память под строку ‘100’ будет выделена менеджером EXE-файла, а освобождаться она будет менеджером DLL. То же произойдет и с памятью под строку ‘100$’, только наоборот.

Для преодоления этой проблемы, разработчики Delphi создали библиотеку BORLNDMM.DLL. Она включает в себя еще один менеджер памяти :). Использование же модуля ShareMem, приводит к тому, что он заменяет встроенный в EXE (DLL) менеджер памяти на менеджер расположенный в BORLNDMM.DLL. Т.е., теперь и EXE-файл и DLL, будут использовать один, общий менеджер памяти.

Здесь важно отметить то, что если какой-либо из программных модулей (EXE или DLL) не будут иметь в списке импорта модуля ShareMem, то вся работа пойдет насмарку. Опять будут работать несколько менеджеров памяти. Опять будет бардак.

Можно обойтись и без внешнего менеджера памяти (BORLNDMM.DLL). Но для этого, надо например заменить встроенный в DLL менеджер памяти, на менеджер, встроенный в EXE. Такое возможно. Есть даже соответствующая реализация от Emil M. Santos, называемая FastShareMem. Найти ее можно на сайте http://www.codexterity.com. Она тоже требует обязательного указания ее модуля FastShareMem в списках используемых модулей EXE и DLL. Но, она по крайней мере не требует таскать за собой ни каких дополнительных DLL’лек.

Ну вот, наконец-то и все. Теперь, Вы знаете о строках почти столько же как я :).

Конечно, этим тема не исчерпывается. Например, я ничего не рассказал о мультибайтовых строках (MBCS) используемых для мультиязыковых приложений. Может и еще что-то забыл рассказать. Но, не расстраивайтесь. Я свои знания получал, изучая книги, тексты своих и чужих программ, код сгенерированный компилятором, и т.п. Т.е., все из открытых источников. Значит это все доступно и Вам. Главное, чтобы Вы были любознательными, и почаще задавали себе вопросы «Как?», «Почему?», «Зачем?». Тогда во всем сможете разобраться и сами.

Операции со строками Delphi

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

Примеры операции со строками Delphi

1) Функция length возвращает длину указанной строки. Данная функция обладает одним параметром, который представляет собой выражение, имеющее строковый тип данных. В качестве значения функции length выступает целое число, обозначающее количество символов, входящих в состав строки.

Примеры

b:=length(‘na beregu’);

В результате выполнения этих инструкций переменная a пример значение 6, а переменная b получит значение 9. 2)

2) Процедура delete. С помощью процедуры delete можно удалить определенную часть строки. Общий вид процедуры delete выглядит следующим образом:

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

Пример

При выполнении инструкции

переменная st примет значение-строку ‘Город’. 3)

3) Функция роs. С помощью функции pos возможно определение положения подстроки в указанной строке. Общий вид инструкции функции pos представляется так:

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

Пример

При выполнении следующей инструкции:

Переменная n примет значение 2. В случае, если строка не содержит искомую подстроку, то функция pos возвращает значение 0. Приведем пример инструкции оператора while, которая позволит удалить начальные пробелы из указанной строки:

Здесь процедура delete(s, 1, 1) удаляет пробелы до тех пор, пока пробел есть начальный символ строки (то есть пока значение функции pos(‘ ‘,s) совпадает с единицей). Проверка условия length(s) > 0 применяется здесь для того, чтобы учесть возможность включения в строку только одних пробелов.

4) Функция copy выделяет фрагмент указанной строки. Общий вид инструкции функции copy представляется следующим образом:

откуда строка обозначает строковое выражение, включающее строку, фрагмент которой необходимо получить; n обозначает номер первого символа, начиная с которого выделяется подстрока; m обозначает длину выделяемой подстроки.

Пример

При выполнении инструкции

town:=copy(s, 7, 12) ;

переменная town примет значение-строку ‘Екатеринбург‘.

Илон Маск рекомендует:  Как задать цвет активной ссылки
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL