Как найти пробел в строке delphi

RaulGain

0 / 0 / 0

Регистрация: 22.09.2013

Сообщений: 63

1

Поиск символа в строке и последующие действия

12.11.2013, 00:30. Показов 853. Ответов 12

Метки нет (Все метки)


Студворк — интернет-сервис помощи студентам

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

Пока есть такие наброски:

Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
procedure search;
var
    p,j,i,k:integer;
    s:string;
    
begin
    for i:= 0 to memo1.lines.count do
        begin
            s:=memo1.lines[i];
            for j:= 0 to lenght(s) do
                begin
                    p:=antipos(' ', s);
                    if p=0 then showmessage(No)
                    else
                        begin
                            for k:= 0 to p do
                            {и вот тут что-то должно быть}
                        end;                    
                end;
        end;
end;



0



Programming

Эксперт

94731 / 64177 / 26122

Регистрация: 12.04.2006

Сообщений: 116,782

12.11.2013, 00:30

12

northener

пофигист широкого профиля

4656 / 3091 / 854

Регистрация: 15.07.2013

Сообщений: 17,818

12.11.2013, 00:41

2

Delphi
1
2
if Pos(#32,s) > 1 then
  s:=Copy(s,1,Pos(#32,s)-1);



1



RaulGain

0 / 0 / 0

Регистрация: 22.09.2013

Сообщений: 63

12.11.2013, 00:52

 [ТС]

3

Цитата
Сообщение от northener
Посмотреть сообщение

Delphi
1
2
if Pos(#32,s) > 1 then
  s:=Copy(s,1,Pos(#32,s)-1);

Спасибо.
А теперь такой вопрос – у меня это всё проверяется в цикле.
Как вывести те строчки, в который встречается эта s в компонент memo?



0



artemka2008

191 / 50 / 10

Регистрация: 27.09.2013

Сообщений: 516

Записей в блоге: 4

12.11.2013, 01:13

4

Цитата
Сообщение от RaulGain
Посмотреть сообщение

Как вывести те строчки, в который встречается эта s в компонент memo?

Delphi
1
Memo1.lines.add(s);



0



RaulGain

0 / 0 / 0

Регистрация: 22.09.2013

Сообщений: 63

12.11.2013, 09:44

 [ТС]

5

Цитата
Сообщение от artemka2008
Посмотреть сообщение

Delphi
1
Memo1.lines.add(s);

Нет, не то.
Суть в том, что мне нужно вывести строки с содержанием s в ней, т.е. там не только s, но и куча всего другого.



0



пофигист широкого профиля

4656 / 3091 / 854

Регистрация: 15.07.2013

Сообщений: 17,818

12.11.2013, 10:26

6

Цитата
Сообщение от RaulGain
Посмотреть сообщение

мне нужно вывести строки с содержанием s в ней

Поточнее пожалуйста что и куда вывести?



0



0 / 0 / 0

Регистрация: 22.09.2013

Сообщений: 63

12.11.2013, 10:32

 [ТС]

7

Цитата
Сообщение от northener
Посмотреть сообщение

Поточнее пожалуйста что и куда вывести?

Смотрите: находим то, что до первого пробела, пусть это будет ‘пылесос’, и все такие строчки с ‘пылесос’, включая то, что идёт после и до самого конца строки, выводим построчно в компонент memo.



0



northener

пофигист широкого профиля

4656 / 3091 / 854

Регистрация: 15.07.2013

Сообщений: 17,818

12.11.2013, 10:57

8

<telepator on>

Delphi
1
2
3
4
5
if Pos(#32,s) > 1 then
  s:=Copy(s,1,Pos(#32,s)-1);
for i:=0 to Memo1.Lines.Count-1 do
  if Pos(s,Memo1.Lines[i]) <> 0 then
    Memo2.Lines.Add(Memo1.Lines[i]);

<telepator off>
Угадал?



1



RaulGain

0 / 0 / 0

Регистрация: 22.09.2013

Сообщений: 63

12.11.2013, 19:00

 [ТС]

9

Цитата
Сообщение от northener
Посмотреть сообщение

<telepator on>

Delphi
1
2
3
4
5
if Pos(#32,s) > 1 then
  s:=Copy(s,1,Pos(#32,s)-1);
for i:=0 to Memo1.Lines.Count-1 do
  if Pos(s,Memo1.Lines[i]) <> 0 then
    Memo2.Lines.Add(Memo1.Lines[i]);

<telepator off>
Угадал?

Именно то, что нужно.
Спасибо.
А теперь как сделать так, чтобы то, что находится в мемо2 удалить из мемо1?



0



northener

пофигист широкого профиля

4656 / 3091 / 854

Регистрация: 15.07.2013

Сообщений: 17,818

12.11.2013, 19:21

10

Цитата
Сообщение от RaulGain
Посмотреть сообщение

А теперь как сделать так, чтобы то, что находится в мемо2 удалить из мемо1?

А сразу об этом сказать не?

Delphi
1
2
3
4
5
6
7
if Pos(#32,s) > 1 then
  s:=Copy(s,1,Pos(#32,s)-1);
for i:=Memo1.Lines.Count-1 downto 0 do
  if Pos(s,Memo1.Lines[i]) <> 0 then begin
    Memo2.Lines.Add(Memo1.Lines[i]);
    Memo1.Lines.Delete(i);
  end;



0



RaulGain

0 / 0 / 0

Регистрация: 22.09.2013

Сообщений: 63

12.11.2013, 19:35

 [ТС]

11

Цитата
Сообщение от northener
Посмотреть сообщение

А сразу об этом сказать не?

Delphi
1
2
3
4
5
6
7
if Pos(#32,s) > 1 then
  s:=Copy(s,1,Pos(#32,s)-1);
for i:=Memo1.Lines.Count-1 downto 0 do
  if Pos(s,Memo1.Lines[i]) <> 0 then begin
    Memo2.Lines.Add(Memo1.Lines[i]);
    Memo1.Lines.Delete(i);
  end;

Просто это уже по нажатию другой кнопки должно быть.
И тут это уже не подходит, получается.



0



northener

пофигист широкого профиля

4656 / 3091 / 854

Регистрация: 15.07.2013

Сообщений: 17,818

12.11.2013, 19:41

12

Цитата
Сообщение от RaulGain
Посмотреть сообщение

Просто это уже по нажатию другой кнопки должно быть.

Ну тогда

Delphi
1
2
3
for i:=0 to Memo2.Lines.Count-1 do
  if Memo1.Lines.IndexOf(Memo2.Lines[i]) >= 0 then
    Memo1.Lines.Delete(Memo1.Lines.IndexOf(Memo2.Lines[i]));



1



RaulGain

0 / 0 / 0

Регистрация: 22.09.2013

Сообщений: 63

12.11.2013, 19:57

 [ТС]

13

Цитата
Сообщение от northener
Посмотреть сообщение

Ну тогда

Delphi
1
2
3
for i:=0 to Memo2.Lines.Count-1 do
  if Memo1.Lines.IndexOf(Memo2.Lines[i]) >= 0 then
    Memo1.Lines.Delete(Memo1.Lines.IndexOf(Memo2.Lines[i]));

Спасибо.
И, наконец, последний вопрос: как сделать сохранение того, что находится в мемо1 в текстовой файл?
Не просто перезапись, а именно “Сохранить как…”



0



IT_Exp

Эксперт

87844 / 49110 / 22898

Регистрация: 17.06.2006

Сообщений: 92,604

12.11.2013, 19:57

Помогаю со студенческими работами здесь

Поиск символа в строке
Предположим я беру строчку вот так: Memo1-&gt;Lines-&gt;Strings; Как сделать поиск по этой строке, и…

Поиск символа в строке
Здравствуйте. Мне необходимо проверить выделенный фрагмент текста на наличие в конце точки. Если…

Поиск символа в строке
Подскажите пожалуйста есть задача строка &quot;араоролвоарла&quot; ( например) задача : программа должна…

Поиск символа в строке
Здравствуйте. По условию задачи нужно найти все требуемые символы в строке и вывести на экран их…

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:

13

 
Гарри Шалфеевичь
 
(2005-09-29 17:19)
[0]

…или последний пробел в строке ДО опеделенной позиции?

Допустим есть строка :
“Разрешается использование тегов форматирования текста: а для выделения текста программ”
Как мне найти пробел между словами “текста” и  “программ” не знаная об эих словах?
То есть…  
Есть ричедит в который грузится тестовой файл. В результате в ричедите оказываетя порядка 100 – 150 строк разной длины. КАК найти пробелы в строках ДО 120 символа? Именно последний пробел перед 120 символом.

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

Вобщем я фигово излогаю, но как внятнее я не знаю.
Помогите плийз если не трудно…


 
umbra ©
 
(2005-09-29 17:31)
[1]


function FindLastSpace(src: string): integer;
begin
src := LeftStr(src, 120);
src := ReverseStr(src);
Result := Pos(" ", src);
end;


 
Smithson
 
(2005-09-29 17:41)
[2]

[code]
for I := Length(S) downto 1 do
 if S[I] – ” ” then // Нашли!
[/code]


 
han_malign ©
 
(2005-09-29 18:28)
[3]

Result:=0;
len:= Length(str);
if(len > limit)then begin
   Result:=limit;
   while((Result > 0) and (str[Result] <> " ")) dec(Result);
end;


 
Гарри Шалфеевичь
 
(2005-09-29 18:44)
[4]

Спасибо всем большое!!!!
И в праду форум МАСТЕРОВ )))


 
Fay ©
 
(2005-09-29 18:51)
[5]

2 umbra ©   (29.09.05 17:31) [1]
Зачем такие сложности?!


 
begin…end ©
 
(2005-09-29 18:51)
[6]

> Как найти ПОСЛЕДНИЙ пробел в строке?

См. функции AnsiStrRScan или LastDelimiter из модуля SysUtils.


 
umbra ©
 
(2005-09-29 18:59)
[7]


> Fay ©   (29.09.05 18:51) [5]
> Зачем такие сложности?!

Надо ж эти функции как нибудь использовать! Да и наглядней получается.


> begin…end

А у меня в делфи AnsiStrRScan нет


 
Fay ©
 
(2005-09-29 19:15)
[8]

2 umbra ©   (29.09.05 18:59) [7]
А for есть? 8)


 
umbra ©
 
(2005-09-29 19:21)
[9]

2 Fay © (29.09.05 19:15) [8]

Ну надо ж уважать труд создателей делфи! они трудились, функции писали:))


 
begin…end ©
 
(2005-09-29 19:24)
[10]

> umbra ©   (29.09.05 18:59) [7]

А у меня в Delphi AnsiStrRScan есть.


 
Fay ©
 
(2005-09-29 19:35)
[11]

2 begin…end ©   (29.09.05 19:24) [10]

>> А у меня в Delphi AnsiStrRScan есть.
У меня, как выяснилось, тоже. (D7)
Посмотрел. Гуано редкое.


 
begin…end ©
 
(2005-09-29 19:38)
[12]

> Fay ©   (29.09.05 19:35) [11]
> Гуано редкое.

Надеюсь, я в этом не виноват?


 
Fay ©
 
(2005-09-29 19:40)
[13]

2 begin…end ©   (29.09.05 19:38) [12]
Сторона обвинения пока не располагает убедительными доказательствами 8)


 
umbra ©
 
(2005-09-29 19:42)
[14]


> Fay ©  

Как оказалось, и у меня она есть тоже. Если присмотреться к модулю StrUtils, то можно рассмотреть


 
umbra ©
 
(2005-09-29 19:44)
[15]


> StrUtils

Все, пора домой! SysUtils


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

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

Символы

Символ – это одна единица текста. Это буква, цифра, какой-либо знак. Кодовая таблица символов состоит из 256 позиций, т.е. каждый символ имеет свой уникальный код от 0 до 255. Символ с некоторым кодом N записывают так: #N. Прямо так символы и указываются в коде программы. Так как код символа представляет собой число не более 255, то очевидно, что в памяти символ занимает 1 байт. Как известно, менее байта размерности нет. Точнее, она есть – это бит, но работать с битами в программе мы не можем: байт – минимальная единица. Просмотреть таблицу символов и их коды можно с помощью стандартной утилиты “Таблица символов”, входящей в Windows (ярлык расположен в меню Пуск – Программы – Стандартные – Служебные). Но совсем скоро мы и сами напишем нечто подобное.

Строки

Строка, она же текст – это набор символов, любая их последовательность. Соответственно, один символ – это тоже строка, тоже текст. Текстовая строка имеет определённую длину. Длина строки – это количество символов, которые она содержит. Если один символ занимает 1 байт, то строка из N символов занимает соответственно N байт.

Есть и другие кодовые таблицы, в которых 1 символ представлен не одним байтом, а двумя. Это Юникод (Unicode). В таблице Юникода есть символы всех языков мира. К сожалению, работа с Юникодом довольно затруднена и его поддержка пока что носит лишь локальный характер. Delphi не предоставляет возможностей для работы с Юникодом. Программная часть есть, но вот визуальные элементы – формы, кнопки и т.д. не умеют отображать текст в формате Юникода. Будем надеяться, в ближайшем будущем такая поддержка появится. 2 байта также называют словом (word). Отсюда и название соответствующего числового типа данных – Word (число, занимающее в памяти 2 байта, значения от 0 до 65535). Количество “ячеек” в таблице Юникода составляет 65536 и этого вполне достаточно для хранения всех языков мира. Если вы решили, что “1 байт – 256 значений, значит 2 байта – 2*256 = 512 значений”, советую вспомнить двоичную систему и принцип хранения данных в компьютере.

Типы данных

Перейдём непосредственно к программированию. Для работы с символами и строками существуют соответствующие типы данных:

· Char – один символ (т.е. 1 байт);

· String – строка символов, текст (N байт).

Официально строки вмещают лишь 255 символов, однако в Delphi в строку можно записать гораздо больше. Для хранения больших текстов и текстов со специальными символами существуют специальные типы данных AnsiString и WideString (последний, кстати, двухбайтовый, т.е. для Юникода).

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

s:=’text’;

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

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

В скобках указывается максимальная длина строки.

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

Основной операцией со строками является сложение. Подобно числам, строки можно складывать. И если в числах стулья с апельсинами складывать нельзя, то в строках – можно. Сложение строк – это просто их объединение. Пример:

var s: string;
...
s:='123'+'456';
//s = "123456"

Поскольку каждая строка – это последовательность символов, каждый символ имеет свой порядковый номер. В Pascal нумерация символов в строках начинается с 1. Т.е. в строке “ABC” символ “A” – первый, “B” – второй и т.д.

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

var s: string; c: char; 
...
s:='Hello!';
c:=s[2];
//c = "e"

Чуть позже, когда мы будем изучать массивы, станет понятно, что строка – это массив символов. Отсюда следует и форма обращения к отдельным символам.

Обработка строк

Перейдём к функциям и процедурам обработки строк.

Длину строки можно узнать с помощью функции Length(). Функция принимает единственный параметр – строку, а возвращает её длину. Пример:

var Str: String; L: Integer; 
{ ... } 
Str:='Hello!'; 
L:=Length(Str);
//L = 6

Нахождение подстроки в строке

Неотъемлемой задачей является нахождение подстроки в строке. Т.е. задача формулируется так: есть строка S1. Определить, начиная с какой позиции в неё входит строка S2. Без выполнения этой операции ни одну обработку представить невозможно.

Итак, для такого нахождения существует функция Pos(). Функция принимает два параметра: первый – подстроку, которую нужно найти, второй – строку, в которой нужно выполнить поиск. Поиск осуществляется с учётом регистра символов. Если функция нашла вхождение подстроки в строку, возвращается номер позиции её первого вхождения. Если вхождение не найдено, функция даёт результат 0. Пример:

var Str1, Str2: String; P: Integer; 
{ ... } 
Str1:='Hi! How do you do?'; 
Str2:='do'; 
P:=Pos(Str2, Str1);
//P = 9

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

Удалить часть строки можно процедурой Delete(). Следует обратить внимание, что это именно процедура, а не функция – она производит действия непосредственно над той переменной, которая ей передана. Итак, первый параметр – переменная строкового типа, из которой удаляется фрагмент (именно переменная! конкретное значение не задаётся, т.к. процедура не возвращает результат), второй параметр – номер символа, начиная с которого нужно удалить фрагмент, третий параметр – количество символов для удаления. Пример:

var Str1: String; 
{ ... } 
Str1:='Hello, world!'; 
Delete(Str1, 6, 7);
// Str1 = "Hello!"

Следует отметить, что если длина удаляемого фрагмента окажется больше количества символов в строке, начиная с указанной позиции (т.е. “вылезем за край”), функция нормально отработает. Поэтому, если нужно удалить фрагмент из строки с какого-то символа до конца, не нужно вычислять количество этих символов. Лучшим способом будет задать длину самой этой строки.

Вот пример. Допустим, требуется найти в строке первую букву “a” и удалить следующую за ней часть строки. Сделаем следующим образом: позицию буквы в строке найдём функцией Pos(), а фрагмент удалим функцией Delete().

var Str: String; 
{ ... } 
Str:='This is a test.';
Delete(Str,Pos('a',Str),Length(Str));

Попробуем подставить значения и посмотреть, что передаётся функции Delete. Первая буква “a” в строке стоит на позиции 9. Длина всей строки – 15 символов. Значит вызов функции происходит такой: Delete(Str,9,15). Видно, что от буквы “a” до конца строки всего 7 символов… Но функция сделает своё дело, не смотря на эту разницу. Результатом, конечно, будет строка “This is “. Данный пример одновременно показал и комбинирование нескольких функций.

Копирование (извлечение) части строки

Ещё одной важной задачей является копирование части строки. Например, извлечение из текста отдельных слов. Выделить фрагмент строки можно удалением лишних частей, но этот способ неудобен. Функция Copy() позволяет скопировать из строки указанную часть. Функция принимает 3 параметра: текст (строку), откуда копировать, номер символа, начиная с которого скопировать и количество символов для копирования. Результатом работы функции и будет фрагмент строки.

Пример: пусть требуется выделить из предложения первое слово (слова разделены пробелом). На форме разместим Edit1 (TEdit), в который будет введено предложение. Операцию будет выполнять по нажатию на кнопку. Имеем:

procedure TForm1.Button1Click(Sender: TObject);
var s,word: string;
begin
  s:=Edit1.Text;
  word:=Copy(s,1,Pos(' ',s)-1);
  ShowMessage('Первое слово: '+word);
end;

В данном случае из строки копируется фрагмент от начала до первого пробела. Число символов берётся на единицу меньше, т.к. в противном случае пробел также будет скопирован.

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

Если требуется в имеющуюся строку вставить другую строку, можно использовать процедуру Insert(). Первый параметр – строка для вставки, второй – переменная, содержащая строку, куда нужно вставить, третий – позиция (номер символа), начиная с которого будет вставлена строка. Пример:

procedure TForm2.Button1Click(Sender: TObject);
var S: String;
begin
  S:='1234567890';
  Insert('000',S,3);
  ShowMessage(S)
 
end;

В данном случае результатом будет строка “1200034567890”.

Пример “посерьёзнее”

Примеры, приведённые выше, лишь демонстрируют принцип работы со строками с помощью функций Length(), Pos(), Delete() и Copy(). Теперь решим задачу посложнее, которая потребует комбинированного применения этих функций.

Задача: текст, введённый в поле Memo, разбить на слова и вывести их в ListBox по одному на строке. Слова отделяются друг от друга пробелами, точками, запятыми, восклицательными и вопросительными знаками. Помимо этого вывести общее количество слов в тексте и самое длинное из этих слов.

Вот уж да… Задача вовсе не простая. Во-первых, вы сразу должны догадаться, что нужно использовать циклы. Без них никак, ведь мы не знаем, какой текст будет передан программе для обработки. Во-вторых, слова отделяются разными символами – это создаёт дополнительные трудности. Что ж, пойдём по порядку.

Интерфейс: Memo1 (TMemo), Button1 (TButton), ListBox1 (TListBox), Label1, Label2 (TLabel).

Сначала перенесём введённый текст в переменную. Для того, чтобы разом взять весь текст из Memo, обратимся к свойству Lines.Text:

procedure TForm1.Button1Click(Sender: TObject);
var Text: string;
begin
  Text:=Memo1.Lines.Text;
end;

Теперь перейдём к обработке. Первое, что нужно сделать – разобраться с символами-разделителями. Дело в том, что такие символы могут запросто идти подряд, ведь после запятых, точек и других знаков ставится пробел. Обойти эту трудность можно таким простым способом: все разделяющие символы заменим на какой-то один, например на запятую. Для этого пройдём все символы и сделаем необходимые замены. Чтобы определить, является ли символ разделителем, запишем все разделители в отдельную строковую переменную (константу), а затем будем искать в этой строке каждый символ функцией Pos(). Все эти замены будут производиться в переменной, чтобы оригинальный текст в Memo (т.е. на экране) не был затронут. Тем не менее, для проверки промежуточных результатов работы имеет смысл выводить обработанный текст куда-либо. Например, в другое поле Memo. Чтобы пройти все символы, воспользуемся циклом FOR, где переменная пройдёт порядковые номера всех символов, т.е. от 1 до длины строки текста:

procedure TForm1.Button1Click(Sender: TObject);
const DelSym = ' .,!?';
var Text: string; i: integer;
begin
  Text:=Memo1.Lines.Text;
  for i := 1 to Length(Text) do
    if Pos(Text[i],DelSym) > 0 then
      Text[i]:=',';
 
  Memo2.Text:=Text;
end;

Теперь нужно устранить помехи. Во-первых, первый символ не должен быть разделителем, т.е. если первый символ – запятая, его нужно удалить. Далее, если подряд идут несколько запятых, их нужно заменить на одну. И наконец, чтобы корректно обработать весь текст, последним символом должна быть запятая.

if Text[1] = ',' then
    Delete(Text,1,1);
while Pos(',,',Text) > 0 do
  Delete(Text,Pos(',,',Text),1);
if Text[Length(Text)] <> ',' then
  Text:=Text+',';

Здесь замена произведена следующим образом: организован цикл, в котором одна из запятых удаляется, но происходит это до тех пор, пока в тексте есть две идущие подряд запятые.

Ну вот, теперь в тексте не осталось ничего лишнего – только слова, разделённые запятыми. Сначала добьёмся того, чтобы программа извлекла из текста первое слово. Для этого найдём первую запятую, скопируем слово от начала текста до этой запятой, после чего удалим это слово из текста вместе с запятой. Удаление делается для того, чтобы далее можно было, проделав ту же самую операцию, вырезать следующее слово.

var Word: string;
{...}
Word:=Copy(Text,1,Pos(',',Text)-1);
Delete(Text,1,Length(Word)+1);

Теперь в переменной Word у нас слово из текста, а в переменной Text вся остальная часть текста. Вырезанное слово теперь добавляем в ListBox, вызывая ListBox.Items.Add(строка_для_добавления).

Теперь нам нужно организовать такой цикл, который позволил бы вырезать из текста все слова, а не только первое. В данном случае подойдёт скорее REPEAT, чем WHILE. В качестве условия следует указать Length(Text) = 0, т.е. завершить цикл тогда, когда текст станет пустым, т.е. когда мы вырежем из него все слова.

repeat
  Word:=Copy(Text,1,Pos(',',Text)-1);
  Delete(Text,1,Length(Word)+1);
  ListBox1.Items.Add(Word);
until Length(Text) = 0;

Итак, на данный момент имеем:

procedure TForm1.Button1Click(Sender: TObject);
const DelSym = ' .,!?';
var Text,Word: string; i: integer;
begin
  Text:=Memo1.Lines.Text;
  for i := 1 to Length(Text) do
    if Pos(Text[i],DelSym) > 0 then
      Text[i]:=',';
 
  if Text[1] = ',' then
    Delete(Text,1,1);
  while Pos(',,',Text) > 0 do
    Delete(Text,Pos(',,',Text),1);
        
  repeat
    Word:=Copy(Text,1,Pos(',',Text)-1);
    Delete(Text,1,Length(Word)+1);
    ListBox1.Items.Add(Word);
  until Length(Text) = 0;
end;

Если вы сейчас запустите программу, то увидите, что всё отлично работает. За исключением одного момента – в ListBox в конце появились какие-то пустые строки… Возникает вопрос: откуда же они взялись? Об этом вы узнаете в следующем разделе урока, а пока давайте реализуем требуемое до конца.

Количество слов в тексте определить очень просто – не нужно заново ничего писать. Т.к. слова у нас занесены в ListBox, достаточно просто узнать, сколько там строк – ListBox.Items.Count.

Label1.Caption:='Количество слов в тексте: '+IntToStr(ListBox1.Items.Count);

Теперь нужно найти самое длинное из всех слов. Алгоритм нахождения максимального числа таков: принимаем в качестве максимального первое из чисел. Затем проверяем все остальные числа таким образом: если число больше того, которое сейчас записано как максимальное, делаем максимальным это число. В нашем случае нужно искать максимальную длину слова. Для этого можно добавить код в цикл вырезания слов из текста или произвести поиск после добавления всех слов в ListBox. Сделаем вторым способом: организуем цикл по строкам ListBox. Следует отметить, что строки нумеруются с нуля, а не с единицы! В отдельной переменной будем хранить самое длинное слово. Казалось бы, нужно ведь ещё хранить максимальную длину слова, чтобы было с чем сравнивать… Но не нужно заводить для этого отдельную переменную, ведь мы всегда можем узнать длину слова функцией Length(). Итак, предположим, что первое слово самое длинное…

var LongestWord: string;
{...}
  LongestWord:=ListBox1.Items[0];
  for i := 1 to ListBox1.Items.Count-1 do
    if Length(ListBox1.Items[i]) > Length(LongestWord) then
      LongestWord:=ListBox1.Items[i];
 
  Label2.Caption:='Самое длинное слово: '+LongestWord+' ('+IntToStr(Length(LongestWord))+' букв)';

Почему цикл до ListBox.Items.Count-1, а не просто до Count, разберитесь самостоятельно 🙂

Вот теперь всё готово!

procedure TForm1.Button1Click(Sender: TObject);
const DelSym = ' .,!?';
var Text,Word,LongestWord: string; i: integer;
begin
  Text:=Memo1.Lines.Text;
  for i := 1 to Length(Text) do
    if Pos(Text[i],DelSym) > 0 then
      Text[i]:=',';
 
  if Text[1] = ',' then
    Delete(Text,1,1);
  while Pos(',,',Text) > 0 do
    Delete(Text,Pos(',,',Text),1);
 
  Text:=AnsiReplaceText(Text,Chr(13),'');
  Text:=AnsiReplaceText(Text,Chr(10),'');
 
  repeat
    Word:=Copy(Text,1,Pos(',',Text)-1);
    Delete(Text,1,Length(Word)+1);
    ListBox1.Items.Add(Word);
  until Length(Text) = 0;
 
  Label1.Caption:='Количество слов в тексте: '+IntToStr(ListBox1.Items.Count);
 
  LongestWord:=ListBox1.Items[0];
  for i := 1 to ListBox1.Items.Count-1 do
    if Length(ListBox1.Items[i]) > Length(LongestWord) then
      LongestWord:=ListBox1.Items[i];
 
  Label2.Caption:='Самое длинное слово: '+LongestWord+' ('+IntToStr(Length(LongestWord))+' букв)';
end;

Работа с символами

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

Помните “Таблицу символов”? Давайте сделаем её сами!

Вывод осуществим в TStringGrid. Этот компонент представляет собой таблицу, где в каждой ячейке записано текстовое значение. Компонент расположен на вкладке Additional (по умолчанию следует прямо за Standard). Перво-наперво настроим нашу табличку. Нам нужны всего две колонки: в одной будем отображать код символа, а в другой – сам символ. Количество колонок задаётся в свойстве с логичным названием ColCount. Устанавливаем его равным 2. По умолчанию у StringGrid задан один фиксированный столбец и одна фиксированная строка (они отображаются серым цветом). Столбец нам не нужен, а вот строка очень кстати, поэтому ставим FixedCols = 0, а FixedRows оставляем = 1.

Заполнение осуществим прямо при запуске программы, т.е. не будем ставить никаких кнопок. Итак, создаём обработчик события OnCreate() формы.

Количество символов в кодовой таблице 256, плюс заголовок – итого 257. Зададим число строк программно (хотя можно задать и в Инспекторе Объекта):

procedure TForm1.FormCreate(Sender: TObject);
begin
  StringGrid1.RowCount:=257;
end;

Вывод делается крайне просто – с помощью цикла. Просто проходим числа от 0 до 255 и выводим соответствующий символ. Также выводим надписи в заголовок. Доступ к ячейкам StringGrid осуществляется с помощью свойства Cells: Cells[номер_столбца,номер_строки]. В квадратных скобках указываются номера столбца и строки (начинаются с нуля). Значения текстовые.

procedure TForm1.FormCreate(Sender: TObject);
var
  i: Integer;
begin
  StringGrid1.RowCount:=257;
  StringGrid1.Cells[0,0]:='Код';
  StringGrid1.Cells[1,0]:='Символ';
  for i := 0 to 255 do
  begin
    StringGrid1.Cells[0,i+1]:=IntToStr(i);
    StringGrid1.Cells[1,i+1]:=Chr(i);
  end;
end;

Запускаем, смотрим.

Специальные символы

Если вы внимательно посмотрите на нашу таблицу, то увидите, что многие символы отображаются в виде квадратиков. Нет, это не значки. Так отображаются символы, не имеющие визуального отображения. Т.е. символ, например, с кодом 13 существует, но он невидим. Эти символы используются в дополнительных целях. К примеру, символ #0 (т.е. символ с кодом 0) часто применяется для указания отсутствия символа. Существуют также строки, называемые null-terminated – это строки, заканчивающиеся символом #0. Такие строки используются в языке Си.
По кодам можно опознавать нажатия клавиш. К примеру, клавиша Enter имеет код 13, Escape – 27, пробел – 32, Tab – 9 и т.д.

Давайте добавим в нашу программу возможность узнать код любой клавиши. Для этого обработаем событие формы OnKeyPress(). Чтобы этот механизм работал, необходимо установить у формы KeyPreview = True.

procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
  ShowMessage('Код нажатой клавиши: '+IntToStr(Ord(Key)));
end;

Здесь мы выводим окошко с текстом. У события есть переменная Key, в которой хранится символ, соответствующий нажатой клавише. С помощью функции Ord() узнаём код этого символа, а затем функцией IntToStr() преобразуем это число в строку.

Пример “посерьёзнее” – продолжение

Вернёмся к нашему примеру. Пришло время выяснить, откуда в ListBox берутся пустые строки. Дело в том, что они не совсем пустые. Да, визуально они пусты, но на самом деле в каждой из них по 2 специальных символа. Это символы с кодами 13 и 10 (т.е. строка #13#10). В Windows такая последовательность этих двух не визуальных символов означает конец текущей строки и начало новой строки. Т.е. в любом файле и вообще где угодно переносы строк – это два символа. А весь текст, соответственно, остаётся непрерывной последовательностью символов. Эти символы можно (и даже нужно) использовать в случаях, когда требуется вставить перенос строки.

Доведём нашу программу по поиску слов до логического конца. Итак, чтобы избавиться от пустых строк, нам нужно удалить из текста символы #13 и #10. Сделать это можно с помощью цикла, по аналогии с тем, как мы делали замену двух запятых на одну:

while Pos(Chr(13),Text) > 0 do
  Delete(Text,Pos(Chr(13),Text),1);
 
while Pos(Chr(10),Text) > 0 do
  Delete(Text,Pos(Chr(10),Text),1);

Ну вот – теперь программа полностью работоспособна!

Дополнительные функции для работы со строками – модуль StrUtils

Дополнительный модуль StrUtils.pas содержит дополнительные функции для работы со строками. Среди этих функций множество полезных. Вот краткое описание часто используемых функций:

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

AnsiReplaceStr, AnsiReplaceText (строка, текст_1, текст_2) – функции выполняют замену в строке строка строки текст_1 на текст_2. Функции отличаются только тем, что первая ведёт замену с учётом регистра символов, а вторая – без него.

В нашей программе можно использовать эти функции для вырезания из строки символов #13 и #10 – для этого в качестве текста для замены следует указать пустую строку. Вот решение в одну строку кода:

Text:=AnsiReplaceText(AnsiReplaceText(Text,Chr(13),''),Chr(10),'');

DupeString(строка, число_повторений) – формирует строку, состоящую из строки строка путём повторения её заданное количество раз.

ReverseString(строка) – инвертирует строку (“123” -> “321”).

Также следует упомянуть у функциях преобразования регистра.

UpperCase(строка) – преобразует строку в верхний регистр; LowerCase(строка) – преобразует строку в нижний регистр.

Для преобразования отдельных символов следует использовать эти же функции.

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

Скриншоты программ, описанных в статье

0018_01

Программа извлечения слов из текста

0018_02

Таблица символов

Заключение

Длинный получился урок. Итак, сегодня мы познакомились со строками и символами и научились с ними работать. Изученные приёмы используются практически повсеместно. Не бойтесь экспериментировать – самостоятельно повышайте свой уровень навыков программирования!

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

Для работы со строками в последних версиях 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 вы можете использовать директиву «{$H-}», которая превратит тип string в ShortString. С помощью этого способа вы можете использовать старый 16-битный код Delphi или Turbo Pascal в ваших проектах.

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

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

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

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

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

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

program Project1;
 
{$APPTYPE CONSOLE}
 
{$R *.res}
 
uses
    System.SysUtils, System.StrUtils;
 
var
    str1, str2, str3, str4, str5, str6: string;
    arr4: array of char;
 
begin
    try
 
        //Способ 1: инициализируем строку повторяющимися символами.
        //В результате в str1 будет строка "ААААА".
        str1 := StringOfChar('А', 5);
 
        //Способ 2: инициализируем строку повторяющимися символами.
        //В результате в str2 будет строка "ААААА".
        str2 := string.Create('А', 5);
 
        //Способ 3: инициализируем строку повторяющимися подстроками.
        //В результате в str3 будет строка "ХаХаХаХаХа".
        str3 := DupeString('Ха', 5);
 
        //Способ 4: инициализируем строку символами из массива.
        //В результате в str4 будет строка "Абвгд"
        arr4 := ['А', 'б', 'в', 'г', 'д'];
        str4 := string(arr4);
 
        //Способ 5: инициализируем строку символами из массива.
        //В результате в str5 будет строка "Абвгд"
        str5 := string.Create(['А', 'б', 'в', 'г', 'д']);
 
        //Способ 6: инициализируем строку символами из массива (берём только часть символов).
        //В результате в str6 будет строка "бвг"
        str6 := string.Create(['А', 'б', 'в', 'г', 'д'], 1, 3);
 
        //Отображаем результат.
        Writeln(str1);
        Writeln(str2);
        Writeln(str3);
        Writeln(str4);
        Writeln(str5);
        Writeln(str6);
        Readln;
 
    except
        on E: Exception do
            Writeln(E.ClassName, ': ', E.Message);
    end;
end.

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

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

program Project1;
 
{$APPTYPE CONSOLE}
 
{$R *.res}
 
uses
    System.SysUtils;
 
begin
    try
 
        //В нижний регистр меняются только латинские буквы. Результат будет 'АбВгД - abcde'.
        Writeln(LowerCase('АбВгД - AbCdE'));
        //В верхний регистр меняются только латинские буквы. Результат будет 'АбВгД - ABCDE'.
        Writeln(UpperCase('АбВгД - AbCdE'));
        //В нижний регистр меняются и русские и латинские буквы. Результат будет 'абвгд - abcde'.
        Writeln('АбВгД - AbCdE'.ToLower);
        //В верхний регистр меняются и русские и латинские буквы. Результат будет 'АБВГД - ABCDE'.
        Writeln('АбВгД - AbCdE'.ToUpper);
        //Указываем локаль при изменении регистра. Результат будет 'АБВГД - ABCDE'.
        Writeln('АбВгД - AbCdE'.ToUpper(TLanguages.GetLocaleIDFromLocaleName('ru-RU')));
        //В нижний регистр меняются и русские и латинские буквы. Результат будет 'абвгд - abcde'.
        Writeln('АбВгД - AbCdE'.ToLowerInvariant);
        //В верхний регистр меняются и русские и латинские буквы. Результат будет 'АБВГД - ABCDE'.
        Writeln('АбВгД - AbCdE'.ToUpperInvariant);
 
        Readln;
 
    except
        on E: Exception do
            Writeln(E.ClassName, ': ', E.Message);
    end;
end.

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

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

program Project1;
 
{$APPTYPE CONSOLE}
 
{$R *.res}
 
uses
    System.SysUtils;
 
var
    str1, str2, str3, str4: string;
    stringBuilder: TStringBuilder;
 
begin
    try
 
        //Способ 1: используем оператор +.
        str1 := 'Абвг' + 'деёжз' + 'иклмн' + 'опрст';
 
        // Способ 2: используем функцию Concat.
        str2 := Concat('Абвг', 'деёжз', 'иклмн', 'опрст');
 
        // Способ 3: используем функцию TStringHelper.Join.
        str3 := String.Join('', ['Абвг', 'деёжз', 'иклмн', 'опрст']);
 
        // Способ 4: используем TStringBuilder.
        // Способ 4: используем TStringBuilder.
        stringBuilder := TStringBuilder.Create;
        try
            stringBuilder
                .Append('Абвг')
                .Append('деёжз')
                .Append('иклмн')
                .Append('опрст');
            str4 := stringBuilder.ToString;
        finally
            stringBuilder.Free;
        end;
 
        //Отображаем результат.
        Writeln(str1);
        Writeln(str2);
        Writeln(str3);
        Writeln(str4);
        Readln;
 
    except
        on E: Exception do
            Writeln(E.ClassName, ': ', E.Message);
    end;
end.

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

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

str3 := String.Join(', ', ['Москва', 'Санкт-Петербург', 'Севастополь']);

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

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

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

program Project1;
 
{$APPTYPE CONSOLE}
 
{$R *.res}
 
uses
    System.SysUtils;
 
var
    str1, str2: string;
    stringBuilder: TStringBuilder;
 
begin
    try
 
        //В результате вставки получится строка 'Абв--гд'
        str1 := 'Абвгд';
        Insert('--', str1, 4);
        Writeln(str1);
 
        //В результате вставки получится строка 'Абв--гд'
        str2 := 'Абвгд';
        Writeln(str2.Insert(3, '--')); //Будет отображено 'Абв--гд'.
        Writeln(str2); //Здесь тоже будет отображено 'Абв--гд'.
 
        //В результате вставки получится строка 'Абв--гд'
        stringBuilder := TStringBuilder.Create('Абвгд');
        try
            stringBuilder.Insert(3, '--');
            Writeln(stringBuilder.ToString);
        finally
            stringBuilder.Free;
        end;
 
        Readln;
 
    except
        on E: Exception do
            Writeln(E.ClassName, ': ', E.Message);
    end;
end.

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

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

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

program Project1;
 
{$APPTYPE CONSOLE}
 
{$R *.res}
 
uses
    System.SysUtils;
 
var
    str1, str2, str3: string;
    stringBuilder: TStringBuilder;
 
begin
    try
 
        //Способ 1: используем функцию Delete.
        str1 := 'Абвгд';
        Delete(str1, 2, 2);
 
        //Способ 2: используем функцию TStringHelper.Remove.
        str2 := 'Абвгд';
        str2 := str2.Remove(1, 2);
 
        //Способ 3: удаляем символы внутри TStringBuilder.
        stringBuilder := TStringBuilder.Create('Абвгд');
        try
            stringBuilder.Remove(1, 2);
            str3 := stringBuilder.ToString;
        finally
            stringBuilder.Free;
        end;
 
        //Отображаем результат.
        Writeln(str1);
        Writeln(str2);
        Writeln(str3);
        Readln;
 
    except
        on E: Exception do
            Writeln(E.ClassName, ': ', E.Message);
    end;
end.

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

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

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

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

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

program Project1;
 
{$APPTYPE CONSOLE}
 
{$R *.res}
 
uses
    System.SysUtils, System.StrUtils;
 
var
    str1, str2, str3, str4: string;
    arr5: array of char;
    arr6: TCharArray;
    stringBuilder: TStringBuilder;
 
begin
    try
 
        //Способ 1: копируем три символа слева.
        //В результате в строке str2 будет "Абв".
        str1 := LeftStr('Абвгдеёжз', 3);
 
        //Способ 2: копируем три символа справа.
        //В результате в строке str3 будет "ёжз".
        str2 := RightStr('Абвгдеёжз', 3);
 
        //Способ 3: копируем символы из середины.
        //В результате в строке str1 будет "вгд".
        str3 := Copy('Абвгдеёжз', 3, 3);
 
        //Способ 4: копируем символы из середины.
        //В результате в строке str4 будет "вгд".
        str4 := 'Абвгдеёжз'.Substring(2, 3);
 
        //Способ 5: копируем часть строки в массив символов.
        //В результате в массиве arr5 будет ['в', 'г', 'д'].
        SetLength(arr5, 3);
        'Абвгдеёжз'.CopyTo(2, arr5, 0, 3);
 
        //Способ 6: копируем часть символов из TStringBuilder в массив символов.
        //В результате в массиве arr6 будет ['в', 'г', 'д'].
        stringBuilder := TStringBuilder.Create('Абвгдеёжз');
        try
            SetLength(arr6, 3);
            stringBuilder.CopyTo(2, arr6, 0, 3);
        finally
            stringBuilder.Free;
        end;
 
        //Отображаем результат.
        Writeln(str1);
        Writeln(str2);
        Writeln(str3);
        Writeln(str4);
        Writeln(string(arr5));
        Writeln(string(arr6));
        Readln;
 
    except
        on E: Exception do
            Writeln(E.ClassName, ': ', E.Message);
    end;
end.

Первые два способа копируют часть строки слева (функция 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 сравнивают строки на соответствие.

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

program Project1;
 
{$APPTYPE CONSOLE}
 
{$R *.res}
 
uses
    System.SysUtils, System.StrUtils, Winapi.Windows;
 
var
    stringBuilder1, stringBuilder2: TStringBuilder;
 
begin
    try
 
        //Сравнение строк с помощью операторов (регистрозависимое).
        //В результате будет TRUE (т.е. строка 1 сортируется до строки 2).
        Writeln('Арбуз' < 'Банан');
        //В результате будет TRUE (т.е. строка 1 сортируется после строки 2).
        Writeln('Арбуз' > 'Арбалет');
        //В результате будет TRUE (т.е. строка 1 сортируется до строки 2 или строки равны).
        Writeln('Арбуз' <= 'арбуз');
        //В результате будет FALSE (т.е. строки не равны).
        Writeln('Арбуз' = 'арбуз');
 
        //Сравнение с помощью регистрозависимых функций.
        //Результат будет FALSE.
        Writeln('Арбуз'.Equals('арбуз'));
        //Результат будет TRUE.
        Writeln('Банан'.Equals('Банан'));
        //Результат будет FALSE.
        Writeln(SameStr('Арбуз', 'арбуз'));
        //Результат будет TRUE.
        Writeln(SameStr('Банан', 'Банан'));
        //Результат будет -1 (т.е. строка 1 сортируется до строки 2).
        Writeln(string.CompareOrdinal('Арбуз', 'Банан'));
        //Результат будет -1 (т.е. строка 1 сортируется до строки 2).
        Writeln(StrComp('Арбуз', 'Банан'));
        //Сравниваем только первые 2 символа. Результат будет -1 (т.е. строка 1 сортируется до строки 2).
        Writeln(StrLComp('Арбуз', 'Банан', 2));
        //Результат будет -1 (т.е. строка 1 сортируется до строки 2).
        Writeln('Арбуз'.CompareTo('Банан'));
        //Результат будет 19 (т.е. строка 1 сортируется после строки 2).
        Writeln('Арбуз'.CompareTo('Арбалет'));
        //Результат будет -1 (т.е. строка 1 сортируется до строки 2).
        Writeln(CompareStr('Арбуз', 'Банан'));
        //Результат будет 19 (т.е. строка 1 сортируется после строки 2).
        Writeln(CompareStr('Арбуз', 'Арбалет'));
 
        //Сравнение с помощью регистроНЕзависимых функций (работает только для латинских букв).
        //Результат будет FALSE.
        Writeln(SameText('Арбуз', 'арбуз'));
        //Результат будет -32 (т.е. строка 1 сортируется до строки 2).
        Writeln(StrIComp('Арбуз', 'арбуз'));
        //Сравниваем только первые 2 символа. Результат будет -32 (т.е. строка 1 сортируется до строки 2).
        Writeln(StrLIComp('Арбуз', 'арбуз', 2));
        //Результат будет -32 (т.е. строка 1 сортируется до строки 2).
        Writeln(CompareText('Арбуз', 'арбуз'));
        //Результат будет -32 (т.е. строка 1 сортируется до строки 2).
        Writeln(string.CompareText('Арбуз', 'арбуз'));
        //Результат будет 0 (т.е. строки 1 и 2 равны).
        Writeln(string.CompareText('Watermelon', 'watermelon'));
        //Результат будет 0 (т.е. строки 1 и 2 равны).
        Writeln(StrIComp('Watermelon', 'watermelon'));
        //Сравниваем только первые 2 символа. Результат будет 0 (т.е. строки 1 и 2 равны).
        Writeln(StrLIComp('Watermelon', 'watermelon', 2));
        //Результат будет 0 (т.е. строки 1 и 2 равны).
        Writeln(CompareText('Watermelon', 'watermelon'));
 
        //Сравнение с помощью регистроНЕзависимых функций (использование пользовательской локали).
        //Результат будет TRUE.
        Writeln(SameText('Арбуз', 'арбуз', TLocaleOptions.loUserLocale));
        //Результат будет 0 (т.е. строки 1 и 2 равны).
        Writeln(CompareText('Арбуз', 'арбуз', TLocaleOptions.loUserLocale));
 
        //Сравнение с помощью функции TStringHelper.Compare.
        //Регистрозависимое сравнение. В результате будет 1 (т.е. строка 1 сортируется после строки 2).
        Writeln(string.Compare('Арбуз', 'арбуз'));
        //РегистроНЕзависимое сравнение. В результате будет 0 (т.е. строки 1 и 2 одинаковые).
        Writeln(string.Compare('Арбуз', 'арбуз', true));
        //РегистроНЕзависимое сравнение с игнорированием символов и знаков препинания.
        //В результате будет 0 (т.е. строки 1 и 2 одинаковые).
        Writeln(string.Compare('Арбуз!', '-арбуз',
                [TCompareOption.coIgnoreSymbols, TCompareOption.coIgnoreCase]));
        //Сравнение цифр как чисел, а не как строки.
        //В результате будет -1 (т.е. первое число меньше чем второе).
        Writeln(string.Compare('2', '10', [TCompareOption.coDigitAsNumbers]));
        //Сравнение цифр как строки.
        //В результате будет 1 (т.е. строка 1 сортируется после строки 2).
        Writeln(string.Compare('2', '10'));
        //РегистроНЕзависимое сравнение с определённым языком и регионом. В результате будет 0 (т.е. строки 1 и 2 одинаковые).
        Writeln(string.Compare('Арбуз', 'арбуз', true, TLanguages.GetLocaleIDFromLocaleName('ru-RU')));
 
        //Сравнение двух строк в двух экземплярах класса TStringBuilder (регистрозависимое).
        stringBuilder1 := TStringBuilder.Create('Арбуз');
        try
            stringBuilder2 := TStringBuilder.Create('арбуз');
            try
                //Результат будет FALSE.
                Writeln(stringBuilder1.Equals(stringBuilder2));
 
                //Результат будет TRUE.
                stringBuilder2.Clear;
                stringBuilder2.Append('Арбуз');
                Writeln(stringBuilder1.Equals(stringBuilder2));
            finally
                stringBuilder2.Free;
            end;
        finally
            stringBuilder1.Free;
        end;
 
        Readln;
 
    except
        on E: Exception do
            Writeln(E.ClassName, ': ', E.Message);
    end;
end.

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

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

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

program Project1;
 
{$APPTYPE CONSOLE}
 
{$R *.res}
 
uses
    System.SysUtils;
 
begin
    try
 
        //Поиск с первого символа. В результате отобразится 8.
        Writeln(Pos('строка', 'Первая строка, вторая строка', 1));
        //Поиск с десятого символа. В результате отобразится 23.
        Writeln(Pos('строка', 'Первая строка, вторая строка', 10));
        //Поиск несуществующей подстроки. В результате отобразится 0.
        Writeln(Pos('третья', 'Первая строка, вторая строка', 1));
 
        Readln;
 
    except
        on E: Exception do
            Writeln(E.ClassName, ': ', E.Message);
    end;
end.

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

program Project1;
 
{$APPTYPE CONSOLE}
 
{$R *.res}
 
uses
    System.SysUtils;
 
begin
    try
 
        //Поиск с начала строки. В результате отобразится 7.
        Writeln('Первая строка, вторая строка'.IndexOf('строка'));
        //Поиск с десятого символа до конца. В результате отобразится 22.
        Writeln('Первая строка, вторая строка'.IndexOf('строка', 9));
        //Поиск несуществующей подстроки. В результате отобразится -1.
        Writeln('Первая строка, вторая строка'.IndexOf('третья'));
        //Поиск с начала только среди первых 10-ти символов. В результате отобразится -1.
        Writeln('Первая строка, вторая строка'.IndexOf('строка', 0, 10));
        //Поиск с начала только среди первых 20-ти символов. В результате отобразится 7.
        Writeln('Первая строка, вторая строка'.IndexOf('строка', 0, 20));
 
        //Поиск с конца строки. В результате отобразится 22.
        Writeln('Первая строка, вторая строка'.LastIndexOf('строка'));
        //Поиск с двадцать третьего символа и до начала. В результате отобразится 7.
        Writeln('Первая строка, вторая строка'.LastIndexOf('строка', 22));
        //Поиск с конца только среди последних 10 символов. В результате отобразится -1.
        Writeln('Первая строка, вторая строка, третья'.LastIndexOf('строка', 36, 10));
        //Поиск с конца только среди последних 20 символов. В результате отобразится 22.
        Writeln('Первая строка, вторая строка, третья'.LastIndexOf('строка', 36, 20));
 
        Readln;
 
    except
        on E: Exception do
            Writeln(E.ClassName, ': ', E.Message);
    end;
end.

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

program Project1;
 
{$APPTYPE CONSOLE}
 
{$R *.res}
 
uses
    System.SysUtils, System.StrUtils;
 
begin
    try
 
        //В результате отобразится TRUE.
        Writeln(ContainsStr('Раз, два, три, четыре, пять', 'Раз'));
        //В результате отобразится FALSE.
        Writeln(ContainsStr('Раз, два, три, четыре, пять', 'Два'));
        //В результате отобразится TRUE.
        Writeln(ContainsText('Раз, два, три, четыре, пять', 'Три'));
        //В результате отобразится TRUE.
        Writeln('Раз, два, три, четыре, пять'.Contains('четыре'));
        //В результате отобразится FALSE.
        Writeln('Раз, два, три, четыре, пять'.Contains('Пять'));
 
        Readln;
 
    except
        on E: Exception do
            Writeln(E.ClassName, ': ', E.Message);
    end;
end.

Дополнительно есть функции проверяющие, наличие определённой подстроки в начале или в конце текста. Это функции 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 ведётся для текущей локали. Т.е. если на компьютере будет установлена английская локаль, то регистронезависимый поиск по русскому тексту работать не будет.

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

program Project1;
 
{$APPTYPE CONSOLE}
 
{$R *.res}
 
uses
    System.SysUtils, System.StrUtils;
 
begin
    try
 
        //Ищем подстроку в начале строки. Результат будет TRUE.
        Writeln(StartsStr('Раз', 'Раз, два, три'));
        //Ищем подстроку в начале строки. Результат будет FALSE.
        Writeln(StartsStr('раз', 'Раз, два, три'));
        //Ищем подстроку в начале строки. Результат будет FALSE.
        Writeln(StartsStr('два', 'Раз, два, три'));
 
        //Ищем подстроку в начале строки. Результат будет TRUE.
        Writeln(StartsText('Раз', 'Раз, два, три'));
        //Ищем подстроку в начале строки. Результат будет TRUE.
        Writeln(StartsText('раз', 'Раз, два, три'));
        //Ищем подстроку в начале строки. Результат будет FALSE.
        Writeln(StartsText('два', 'Раз, два, три'));
 
        //Ищем подстроку в начале строки. Результат будет TRUE.
        Writeln('Раз, два, три'.StartsWith('Раз'));
        //Ищем подстроку в начале строки. Результат будет FALSE.
        Writeln('Раз, два, три'.StartsWith('раз'));
        //Ищем подстроку в начале строки. Результат будет FALSE (для кириллицы).
        Writeln('Раз, два, три'.StartsWith('раз', true));
        //Ищем подстроку в начале строки. Результат будет TRUE (для латиницы).
        Writeln('One, two, three'.StartsWith('one', true));
        //Ищем подстроку в начале строки. Результат будет FALSE.
        Writeln('Раз, два, три'.StartsWith('два'));
 
        //Ищем подстроку в конце строки. Результат будет TRUE.
        Writeln(EndsStr('три', 'Раз, два, три'));
        //Ищем подстроку в конце строки. Результат будет FALSE.
        Writeln(EndsStr('Три', 'Раз, два, три'));
        //Ищем подстроку в конце строки. Результат будет FALSE.
        Writeln(EndsStr('два', 'Раз, два, три'));
 
        //Ищем подстроку в конце строки. Результат будет TRUE.
        Writeln(EndsText('три', 'Раз, два, три'));
        //Ищем подстроку в конце строки. Результат будет TRUE.
        Writeln(EndsText('Три', 'Раз, два, три'));
        //Ищем подстроку в конце строки. Результат будет FALSE.
        Writeln(EndsText('два', 'Раз, два, три'));
 
        //Ищем подстроку в конце строки. Результат будет TRUE.
        Writeln(string.EndsText('три', 'Раз, два, три'));
        //Ищем подстроку в конце строки. Результат будет TRUE.
        Writeln(string.EndsText('Три', 'Раз, два, три'));
        //Ищем подстроку в конце строки. Результат будет FALSE.
        Writeln(string.EndsText('два', 'Раз, два, три'));
 
        //Ищем подстроку в конце строки. Результат будет TRUE.
        Writeln('Раз, два, три'.EndsWith('три'));
        //Ищем подстроку в конце строки. Результат будет FALSE.
        Writeln('Раз, два, три'.EndsWith('Три'));
        //Ищем подстроку в конце строки. Результат будет TRUE.
        Writeln('Раз, два, три'.EndsWith('Три', true));
        //Ищем подстроку в конце строки. Результат будет FALSE.
        Writeln('Раз, два, три'.EndsWith('два'));
 
        Readln;
 
    except
        on E: Exception do
            Writeln(E.ClassName, ': ', E.Message);
    end;
end.

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

program Project1;
 
{$APPTYPE CONSOLE}
 
{$R *.res}
 
uses
    System.SysUtils, System.RegularExpressions;
 
var
    regEx: TRegEx;
    match: TMatch;
    matches: TMatchCollection;
 
begin
    try
 
        //Ищем в строке любой IP-адрес, с начала строки.
        regEx := TRegEx.Create('bd{1,3}.d{1,3}.d{1,3}.d{1,3}b');
        match := regEx.Match('В этой строке два IP-адреса 192.168.1.1 и 192.168.1.15');
        //Найдена ли подстрока. Результат будет TRUE.
        Writeln(match.Success);
        //Номер первого символа найденной подстроки. Результат будет 29.
        Writeln(match.Index);
        //Длина найденной подстроки. Результат будет 11.
        Writeln(match.Length);
        //Найденная подстрока. Результат будет 192.168.1.1.
        Writeln(match.Value);
 
        //Ищем следующий IP-адрес в этой же строке.
        match := match.NextMatch;
        //Найдена ли следующая подстрока. Результат будет TRUE.
        Writeln(match.Success);
        //Номер первого символа найденной подстроки. Результат будет 43.
        Writeln(match.Index);
        //Длина найденной подстроки. Результат будет 12.
        Writeln(match.Length);
        //Найденная подстрока. Результат будет 192.168.1.15.
        Writeln(match.Value);
 
        //Ищем следующий IP-адрес в этой же строке.
        match := match.NextMatch;
        //Найдена ли следующая подстрока. Результат будет FALSE.
        Writeln(match.Success);
 
        //Ищем адреса почтовых ящиков в тексте, игнорируя регистр.
        regEx := TRegEx.Create('b[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,}b', [roIgnoreCase]);
        matches := regEx.Matches('В этой Этот адрес электронной почты защищён от спам-ботов. У вас должен быть включен JavaScript для просмотра.
  строке Этот адрес электронной почты защищён от спам-ботов. У вас должен быть включен JavaScript для просмотра.
  содержатся три Этот адрес электронной почты защищён от спам-ботов. У вас должен быть включен JavaScript для просмотра.
  почтовых адреса.');
        //В результате будет выдано три адреса:
        //Этот адрес электронной почты защищён от спам-ботов. У вас должен быть включен JavaScript для просмотра.
 
        //Этот адрес электронной почты защищён от спам-ботов. У вас должен быть включен JavaScript для просмотра.
 
        //Этот адрес электронной почты защищён от спам-ботов. У вас должен быть включен JavaScript для просмотра.
 
        for match in matches do
            Writeln(match.Value);
 
        Readln;
 
    except
        on E: Exception do
            Writeln(E.ClassName, ': ', E.Message);
    end;
end.

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

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

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

program Project1;
 
{$APPTYPE CONSOLE}
 
{$R *.res}
 
uses
    System.SysUtils, System.StrUtils, Winapi.Windows;
 
begin
    try
 
        //Ищем символ 'р' или 'о'. В результате будет 2.
        Writeln('Это строка!'.IndexOfAny(['р', 'о']));
        //Ищем символ 'р' или 'о' начиная с пятого символа. В результате будет 6.
        Writeln('Это строка!'.IndexOfAny(['р', 'о'], 4));
        //Ищем символ 'р' или 'о' с пятого по шестой символ. В результате будет -1.
        Writeln('Это строка!'.IndexOfAny(['р', 'о'], 4, 2));
        //Ищем символ 'р' или 'о' с конца строки. В результате будет 7.
        Writeln('Это строка!'.LastIndexOfAny(['р', 'о']));
        //Ищем символ 'р' или 'о' начиная с пятого символа и до начала. В результате будет 2.
        Writeln('Это строка!'.LastIndexOfAny(['р', 'о'], 4));
        //Ищем символ 'р' или 'о' с пятого по третий символ. В результате будет 2.
        Writeln('Это строка!'.LastIndexOfAny(['р', 'о'], 4, 3));
        //Ищем символ 'р' или 'о', но не среди символов заключенных в кавычки. В результате будет 8.
        Writeln('"Это" строка!'.IndexOfAnyUnquoted(['р', 'о'], '"', '"'));
        //Ищем символ 'р' или 'о', но не среди символов заключенных в скобки, в том числе вложенных. В результате будет 17.
        Writeln('(Это (вторая)) строка!'.IndexOfAnyUnquoted(['р', 'о'], '(', ')'));
 
        Readln;
 
    except
        on E: Exception do
            Writeln(E.ClassName, ': ', E.Message);
    end;
end.

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

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

program Project1;
 
{$APPTYPE CONSOLE}
 
{$R *.res}
 
uses
    System.SysUtils, System.StrUtils, System.RegularExpressions;
 
var
    stringBuilder: TStringBuilder;
    regEx: TRegEx;
 
begin
    try
 
        //Ищет все подстроки в строке и заменяет их на новые (регистрозависимый поиск).
        //В результате будет 'Раз, два, три, два'.
        Writeln(ReplaceStr('Раз, четыре, три, четыре', 'четыре', 'два'));
        //Ищет все подстроки в строке и заменяет их на новые (регистрозависимый поиск).
        //В результате будет 'Раз, Четыре, три, два'.
        Writeln(ReplaceStr('Раз, Четыре, три, четыре', 'четыре', 'два'));
 
        //Ищет все подстроки в строке и заменяет их на новые (регистронезависимый поиск).
        //В результате будет 'Раз, два, три, два'.
        Writeln(ReplaceText('Раз, четыре, три, четыре', 'четыре', 'два'));
        //Ищет все подстроки в строке и заменяет их на новые (регистронезависимый поиск).
        //В результате будет 'Раз, два, три, два'.
        Writeln(ReplaceText('Раз, Четыре, три, четыре', 'четыре', 'два'));
 
        //Ищет только первую подстроку в строке и заменяет её на новую.
        //В результате будет 'Раз, два, три, четыре'.
        Writeln(StringReplace('Раз, четыре, три, четыре', 'четыре', 'два', []));
        //Ищет все подстроки в строке и заменяет их на новые.
        //В результате будет 'Раз, два, три, два'.
        Writeln(StringReplace('Раз, четыре, три, четыре', 'четыре', 'два', [rfReplaceAll]));
        //Пример регистрозависимого поиска и замены подстрок.
        //В результате будет 'Раз, Четыре, три, два'.
        Writeln(StringReplace('Раз, Четыре, три, четыре', 'четыре', 'два', [rfReplaceAll]));
        //Пример регистронезависимого поиска и замены подстрок.
        //В результате будет 'Раз, два, три, два'.
        Writeln(StringReplace('Раз, Четыре, три, четыре', 'четыре', 'два', [rfReplaceAll, rfIgnoreCase]));
 
        //Ищет все подстроки в строке и заменяет их на новые
        //(т.к. по умолчанию установлен флаг rfReplaceAll).
        //В результате будет 'Раз, два, три, два'.
        Writeln('Раз, четыре, три, четыре'.Replace('четыре', 'два'));
        //Ищет только первую подстроку в строке и заменяет её на новую
        //(т.к нет флага rfReplaceAll).
        //В результате будет 'Раз, два, три, четыре'.
        Writeln('Раз, четыре, три, четыре'.Replace('четыре', 'два', []));
 
        //Пример регистрозависимого поиска и замены подстрок
        //(т.к. по умолчанию не установлен флаг rfIgnoreCase).
        //В результате будет 'Раз, Четыре, три, два'.
        Writeln('Раз, Четыре, три, четыре'.Replace('четыре', 'два'));
        //Пример регистронезависимого поиска и замены подстрок
        //(т.к. установлен флаг rfIgnoreCase).
        //В результате будет 'Раз, два, три, четыре'.
        Writeln('Раз, Четыре, три, четыре'.Replace('четыре', 'два', [rfIgnoreCase]));
 
        stringBuilder := TStringBuilder.Create;
        try
            //Ищет все подстроки в строке и заменяет их на новые.
            //Результат будет 'Раз, два, три, два'.
            stringBuilder.Append('Раз, четыре, три, четыре');
            Writeln(stringBuilder.Replace('четыре', 'два').ToString);
 
            //Ищет все подстроки в строке и заменяет их на новые.
            //Результат будет 'Раз, Четыре, три, два'.
            stringBuilder.Clear;
            stringBuilder.Append('Раз, Четыре, три, четыре');
            Writeln(stringBuilder.Replace('четыре', 'два').ToString);
 
            //Ищет все подстроки начиная с 4-го символа в пределах 10-ти символов и заменяет их на новые.
            //Результат будет 'Раз, два, три, четыре'.
            stringBuilder.Clear;
            stringBuilder.Append('Раз, четыре, три, четыре');
            Writeln(stringBuilder.Replace('четыре', 'два', 3, 10).ToString);
        finally
            stringBuilder.Free;
        end;
 
        //Ищем и убираем HTML тэги из строки.
        //В результате получится: Здесь содержатся выделенное и подчёркнутое слова и ссылка.
        regEx := TRegEx.Create('<([A-Z][A-Z0-9]*)b[^>]*>(.*?)</1>', [roIgnoreCase]);
        Writeln(regEx.Replace('Здесь содержатся <b>выделенное</b> и <u>подчёркнутое</u> слова и <a href="http://www.proghouse.ru">ссылка</a>.', '2'));
 
        //Ищем определённое слово и заменяем его звёздочками.
        //В результате получится: Закрываем *** слова звёздами. *** слов не будет! *** слово - это ***!
        regEx := TRegEx.Create('плох[ио][емх]?', [roIgnoreCase]);
        Writeln(regEx.Replace('Закрываем плохие слова звёздами. Плохих слов не будет! Плохое слово - это плохо!', '***'));
 
 
        Readln;
 
    except
        on E: Exception do
            Writeln(E.ClassName, ': ', E.Message);
    end;
end.

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

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

program Project1;
 
{$APPTYPE CONSOLE}
 
{$R *.res}
 
uses
    System.SysUtils;
 
begin
    try
 
        //Удаляем пробелы и управляющие символы в начале и конце строки.
        //Результат будет 'Строка без лишних пробелов и управляющих символов!'.
        Writeln(Trim(#13#10' Строка без лишних пробелов и управляющих символов! '#13#10));
        //Удаляем пробелы и управляющие символы в начале и конце строки.
        //Результат будет 'Строка без лишних пробелов и управляющих символов!'.
        Writeln(#13#10' Строка без лишних пробелов и управляющих символов! '#13#10.Trim);
        //Удаляем только символы #13 и #10 в начале и конце строки.
        //Результат будет ' Строка без лишних пробелов и управляющих символов! '.
        Writeln(#13#10' Строка без лишних пробелов и управляющих символов! '#13#10.Trim([#13, #10]));
        //Удаляем пробелы и управляющие символы только в начале строки.
        //Результат будет 'Строка без лишних пробелов и управляющих символов! '#13#10.
        Writeln(TrimLeft(#13#10' Строка без лишних пробелов и управляющих символов! '#13#10));
        //Удаляем пробелы и управляющие символы только в начале строки.
        //Результат будет 'Строка без лишних пробелов и управляющих символов! '#13#10.
        Writeln(#13#10' Строка без лишних пробелов и управляющих символов! '#13#10.TrimLeft);
        //Удаляем пробелы и управляющие символы только в конце строки.
        //Результат будет #13#10' Строка без лишних пробелов и управляющих символов!'.
        Writeln(TrimRight(#13#10' Строка без лишних пробелов и управляющих символов! '#13#10));
        //Удаляем пробелы и управляющие символы только в конце строки.
        //Результат будет #13#10' Строка без лишних пробелов и управляющих символов!'.
        Writeln(#13#10' Строка без лишних пробелов и управляющих символов! '#13#10.TrimRight);
 
        Readln;
 
    except
        on E: Exception do
            Writeln(E.ClassName, ': ', E.Message);
    end;
end.

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

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

program Project1;
 
{$APPTYPE CONSOLE}
 
{$R *.res}
 
uses
    System.SysUtils;
 
begin
    try
 
        //Дополняем числа пробелами. В результате получится:
        //'  123'
        //'12345'
        //' 1234'
        Writeln('123'.PadLeft(5));
        Writeln('12345'.PadLeft(5));
        Writeln('1234'.PadLeft(5));
 
        //Дополняем числа нулями. В результате получится.
        //'00123'
        //'12345'
        //'01234'
        Writeln('123'.PadLeft(5, '0'));
        Writeln('12345'.PadLeft(5, '0'));
        Writeln('1234'.PadLeft(5, '0'));
 
        //Дополняем строки чёрточками, чтобы сделать красивое содержание.
        //В результате получится:
        //'Вступление --------- стр. 1'
        //'Доклад ------------- стр. 2'
        //'Выводы ------------- стр. 7'
        //'Заключение --------- стр. 9'
        Writeln('Вступление '.PadRight(20, '-') + ' стр. 1');
        Writeln('Доклад '.PadRight(20, '-') + ' стр. 2');
        Writeln('Выводы '.PadRight(20, '-') + ' стр. 7');
        Writeln('Заключение '.PadRight(20, '-') + ' стр. 9');
 
        Readln;
 
    except
        on E: Exception do
            Writeln(E.ClassName, ': ', E.Message);
    end;
end.

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

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

Tags:
Учебники по программированию
Delphi

Добавить комментарий

30 января 2017

Для работы со строками в последних версиях 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 их работа не гарантируется.

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

  • Инициализация строк
  • Изменение регистра
  • Конкатенация строк
  • Вставка подстроки в строку
  • Удаление части строки
  • Копирование части строки
  • Сравнение строк
  • Поиск подстроки в строке
  • Поиск символов в строке
  • Замена подстроки в строке
  • Обрезка пробелов и управляющих символов
  • Выравнивание текста за счёт установки пробелов

Содержимое

  • 1 Строки в Delphi
  • 2 Инициализация строк
  • 3 Изменение регистра
  • 4 Конкатенация строк
  • 5 Вставка подстроки в строку
  • 6 Удаление части строки
  • 7 Копирование части строки
  • 8 Сравнение строк
  • 9 Поиск подстроки в строке
  • 10 Поиск символов в строке
  • 11 Замена подстроки в строке
  • 12 Обрезка пробелов и управляющих символов
  • 13 Выравнивание текста за счёт установки пробелов
  • 14 Вместо заключения

Строки в Delphi

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

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

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

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

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

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

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

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses

    System.SysUtils, System.StrUtils;

var

    str1, str2, str3, str4, str5, str6: string;

    arr4: array of char;

begin

    try

        //Способ 1: инициализируем строку повторяющимися символами.

        //В результате в str1 будет строка “ААААА”.

        str1 := StringOfChar(‘А’, 5);

        //Способ 2: инициализируем строку повторяющимися символами.

        //В результате в str2 будет строка “ААААА”.

        str2 := string.Create(‘А’, 5);

        //Способ 3: инициализируем строку повторяющимися подстроками.

        //В результате в str3 будет строка “ХаХаХаХаХа”.

        str3 := DupeString(‘Ха’, 5);

        //Способ 4: инициализируем строку символами из массива.

        //В результате в str4 будет строка “Абвгд”

        arr4 := [‘А’, ‘б’, ‘в’, ‘г’, ‘д’];

        str4 := string(arr4);

        //Способ 5: инициализируем строку символами из массива.

        //В результате в str5 будет строка “Абвгд”

        str5 := string.Create([‘А’, ‘б’, ‘в’, ‘г’, ‘д’]);

        //Способ 6: инициализируем строку символами из массива (берём только часть символов).

        //В результате в str6 будет строка “бвг”

        str6 := string.Create([‘А’, ‘б’, ‘в’, ‘г’, ‘д’], 1, 3);

        //Отображаем результат.

        Writeln(str1);

        Writeln(str2);

        Writeln(str3);

        Writeln(str4);

        Writeln(str5);

        Writeln(str6);

        Readln;

    except

        on E: Exception do

            Writeln(E.ClassName, ‘: ‘, E.Message);

    end;

end.

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

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses

    System.SysUtils;

begin

    try

        //В нижний регистр меняются только латинские буквы. Результат будет ‘АбВгД – abcde’.

        Writeln(LowerCase(‘АбВгД – AbCdE’));

        //В верхний регистр меняются только латинские буквы. Результат будет ‘АбВгД – ABCDE’.

        Writeln(UpperCase(‘АбВгД – AbCdE’));

        //В нижний регистр меняются и русские и латинские буквы. Результат будет ‘абвгд – abcde’.

        Writeln(‘АбВгД – AbCdE’.ToLower);

        //В верхний регистр меняются и русские и латинские буквы. Результат будет ‘АБВГД – ABCDE’.

        Writeln(‘АбВгД – AbCdE’.ToUpper);

        //Указываем локаль при изменении регистра. Результат будет ‘АБВГД – ABCDE’.

        Writeln(‘АбВгД – AbCdE’.ToUpper(TLanguages.GetLocaleIDFromLocaleName(‘ru-RU’)));

        //В нижний регистр меняются и русские и латинские буквы. Результат будет ‘абвгд – abcde’.

        Writeln(‘АбВгД – AbCdE’.ToLowerInvariant);

        //В верхний регистр меняются и русские и латинские буквы. Результат будет ‘АБВГД – ABCDE’.

        Writeln(‘АбВгД – AbCdE’.ToUpperInvariant);

        Readln;

    except

        on E: Exception do

            Writeln(E.ClassName, ‘: ‘, E.Message);

    end;

end.

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

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses

    System.SysUtils;

var

    str1, str2, str3, str4: string;

    stringBuilder: TStringBuilder;

begin

    try

        //Способ 1: используем оператор +.

        str1 := ‘Абвг’ + ‘деёжз’ + ‘иклмн’ + ‘опрст’;

        // Способ 2: используем функцию Concat.

        str2 := Concat(‘Абвг’, ‘деёжз’, ‘иклмн’, ‘опрст’);

        // Способ 3: используем функцию TStringHelper.Join.

        str3 := String.Join(, [‘Абвг’, ‘деёжз’, ‘иклмн’, ‘опрст’]);

        // Способ 4: используем TStringBuilder.

        // Способ 4: используем TStringBuilder.

        stringBuilder := TStringBuilder.Create;

        try

            stringBuilder

                .Append(‘Абвг’)

                .Append(‘деёжз’)

                .Append(‘иклмн’)

                .Append(‘опрст’);

            str4 := stringBuilder.ToString;

        finally

            stringBuilder.Free;

        end;

        //Отображаем результат.

        Writeln(str1);

        Writeln(str2);

        Writeln(str3);

        Writeln(str4);

        Readln;

    except

        on E: Exception do

            Writeln(E.ClassName, ‘: ‘, E.Message);

    end;

end.

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

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

str3 := String.Join(‘, ‘, [‘Москва’, ‘Санкт-Петербург’, ‘Севастополь’]);

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

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

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses

    System.SysUtils;

var

    str1, str2: string;

    stringBuilder: TStringBuilder;

begin

    try

        //В результате вставки получится строка ‘Абв–гд’

        str1 := ‘Абвгд’;

        Insert(‘–‘, str1, 4);

        Writeln(str1);

        //В результате вставки получится строка ‘Абв–гд’

        str2 := ‘Абвгд’;

        Writeln(str2.Insert(3, ‘–‘)); //Будет отображено ‘Абв–гд’.

        Writeln(str2); //Здесь тоже будет отображено ‘Абв–гд’.

        //В результате вставки получится строка ‘Абв–гд’

        stringBuilder := TStringBuilder.Create(‘Абвгд’);

        try

            stringBuilder.Insert(3, ‘–‘);

            Writeln(stringBuilder.ToString);

        finally

            stringBuilder.Free;

        end;

        Readln;

    except

        on E: Exception do

            Writeln(E.ClassName, ‘: ‘, E.Message);

    end;

end.

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

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

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses

    System.SysUtils;

var

    str1, str2, str3: string;

    stringBuilder: TStringBuilder;

begin

    try

        //Способ 1: используем функцию Delete.

        str1 := ‘Абвгд’;

        Delete(str1, 2, 2);

        //Способ 2: используем функцию TStringHelper.Remove.

        str2 := ‘Абвгд’;

        str2 := str2.Remove(1, 2);

        //Способ 3: удаляем символы внутри TStringBuilder.

        stringBuilder := TStringBuilder.Create(‘Абвгд’);

        try

            stringBuilder.Remove(1, 2);

            str3 := stringBuilder.ToString;

        finally

            stringBuilder.Free;

        end;

        //Отображаем результат.

        Writeln(str1);

        Writeln(str2);

        Writeln(str3);

        Readln;

    except

        on E: Exception do

            Writeln(E.ClassName, ‘: ‘, E.Message);

    end;

end.

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

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

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

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

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses

    System.SysUtils, System.StrUtils;

var

    str1, str2, str3, str4: string;

    arr5: array of char;

    arr6: TCharArray;

    stringBuilder: TStringBuilder;

begin

    try

        //Способ 1: копируем три символа слева.

        //В результате в строке str2 будет “Абв”.

        str1 := LeftStr(‘Абвгдеёжз’, 3);

        //Способ 2: копируем три символа справа.

        //В результате в строке str3 будет “ёжз”.

        str2 := RightStr(‘Абвгдеёжз’, 3);

        //Способ 3: копируем символы из середины.

        //В результате в строке str1 будет “вгд”.

        str3 := Copy(‘Абвгдеёжз’, 3, 3);

        //Способ 4: копируем символы из середины.

        //В результате в строке str4 будет “вгд”.

        str4 := ‘Абвгдеёжз’.Substring(2, 3);

        //Способ 5: копируем часть строки в массив символов.

        //В результате в массиве arr5 будет [‘в’, ‘г’, ‘д’].

        SetLength(arr5, 3);

        ‘Абвгдеёжз’.CopyTo(2, arr5, 0, 3);

        //Способ 6: копируем часть символов из TStringBuilder в массив символов.

        //В результате в массиве arr6 будет [‘в’, ‘г’, ‘д’].

        stringBuilder := TStringBuilder.Create(‘Абвгдеёжз’);

        try

            SetLength(arr6, 3);

            stringBuilder.CopyTo(2, arr6, 0, 3);

        finally

            stringBuilder.Free;

        end;

        //Отображаем результат.

        Writeln(str1);

        Writeln(str2);

        Writeln(str3);

        Writeln(str4);

        Writeln(string(arr5));

        Writeln(string(arr6));

        Readln;

    except

        on E: Exception do

            Writeln(E.ClassName, ‘: ‘, E.Message);

    end;

end.

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

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

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

Конечно, сравнивать строки можно с помощью операторов =<<=>>= и <>. Но кроме этого существуют ещё много функций: StrCompStrIComp, StrLComp, StrLIComp, CompareStr, CompareText, TStringHelper.CompareTStringHelper.CompareOrdinalTStringHelper.CompareToTStringHelper.CompareTextSameStr, 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 сравнивают строки на соответствие.

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses

    System.SysUtils, System.StrUtils, Winapi.Windows;

var

    stringBuilder1, stringBuilder2: TStringBuilder;

begin

    try

        //Сравнение строк с помощью операторов (регистрозависимое).

        //В результате будет TRUE (т.е. строка 1 сортируется до строки 2).

        Writeln(‘Арбуз’ < ‘Банан’);

        //В результате будет TRUE (т.е. строка 1 сортируется после строки 2).

        Writeln(‘Арбуз’ > ‘Арбалет’);

        //В результате будет TRUE (т.е. строка 1 сортируется до строки 2 или строки равны).

        Writeln(‘Арбуз’ <= ‘арбуз’);

        //В результате будет FALSE (т.е. строки не равны).

        Writeln(‘Арбуз’ = ‘арбуз’);

        //Сравнение с помощью регистрозависимых функций.

        //Результат будет FALSE.

        Writeln(‘Арбуз’.Equals(‘арбуз’));

        //Результат будет TRUE.

        Writeln(‘Банан’.Equals(‘Банан’));

        //Результат будет FALSE.

        Writeln(SameStr(‘Арбуз’, ‘арбуз’));

        //Результат будет TRUE.

        Writeln(SameStr(‘Банан’, ‘Банан’));

        //Результат будет -1 (т.е. строка 1 сортируется до строки 2).

        Writeln(string.CompareOrdinal(‘Арбуз’, ‘Банан’));

        //Результат будет -1 (т.е. строка 1 сортируется до строки 2).

        Writeln(StrComp(‘Арбуз’, ‘Банан’));

        //Сравниваем только первые 2 символа. Результат будет -1 (т.е. строка 1 сортируется до строки 2).

        Writeln(StrLComp(‘Арбуз’, ‘Банан’, 2));

        //Результат будет -1 (т.е. строка 1 сортируется до строки 2).

        Writeln(‘Арбуз’.CompareTo(‘Банан’));

        //Результат будет 19 (т.е. строка 1 сортируется после строки 2).

        Writeln(‘Арбуз’.CompareTo(‘Арбалет’));

        //Результат будет -1 (т.е. строка 1 сортируется до строки 2).

        Writeln(CompareStr(‘Арбуз’, ‘Банан’));

        //Результат будет 19 (т.е. строка 1 сортируется после строки 2).

        Writeln(CompareStr(‘Арбуз’, ‘Арбалет’));

        //Сравнение с помощью регистроНЕзависимых функций (работает только для латинских букв).

        //Результат будет FALSE.

        Writeln(SameText(‘Арбуз’, ‘арбуз’));

        //Результат будет -32 (т.е. строка 1 сортируется до строки 2).

        Writeln(StrIComp(‘Арбуз’, ‘арбуз’));

        //Сравниваем только первые 2 символа. Результат будет -32 (т.е. строка 1 сортируется до строки 2).

        Writeln(StrLIComp(‘Арбуз’, ‘арбуз’, 2));

        //Результат будет -32 (т.е. строка 1 сортируется до строки 2).

        Writeln(CompareText(‘Арбуз’, ‘арбуз’));

        //Результат будет -32 (т.е. строка 1 сортируется до строки 2).

        Writeln(string.CompareText(‘Арбуз’, ‘арбуз’));

        //Результат будет 0 (т.е. строки 1 и 2 равны).

        Writeln(string.CompareText(‘Watermelon’, ‘watermelon’));

        //Результат будет 0 (т.е. строки 1 и 2 равны).

        Writeln(StrIComp(‘Watermelon’, ‘watermelon’));

        //Сравниваем только первые 2 символа. Результат будет 0 (т.е. строки 1 и 2 равны).

        Writeln(StrLIComp(‘Watermelon’, ‘watermelon’, 2));

        //Результат будет 0 (т.е. строки 1 и 2 равны).

        Writeln(CompareText(‘Watermelon’, ‘watermelon’));

        //Сравнение с помощью регистроНЕзависимых функций (использование пользовательской локали).

        //Результат будет TRUE.

        Writeln(SameText(‘Арбуз’, ‘арбуз’, TLocaleOptions.loUserLocale));

        //Результат будет 0 (т.е. строки 1 и 2 равны).

        Writeln(CompareText(‘Арбуз’, ‘арбуз’, TLocaleOptions.loUserLocale));

        //Сравнение с помощью функции TStringHelper.Compare.

        //Регистрозависимое сравнение. В результате будет 1 (т.е. строка 1 сортируется после строки 2).

        Writeln(string.Compare(‘Арбуз’, ‘арбуз’));

        //РегистроНЕзависимое сравнение. В результате будет 0 (т.е. строки 1 и 2 одинаковые).

        Writeln(string.Compare(‘Арбуз’, ‘арбуз’, true));

        //РегистроНЕзависимое сравнение с игнорированием символов и знаков препинания.

        //В результате будет 0 (т.е. строки 1 и 2 одинаковые).

        Writeln(string.Compare(‘Арбуз!’, ‘-арбуз’,

                [TCompareOption.coIgnoreSymbols, TCompareOption.coIgnoreCase]));

        //Сравнение цифр как чисел, а не как строки.

        //В результате будет -1 (т.е. первое число меньше чем второе).

        Writeln(string.Compare(‘2’, ’10’, [TCompareOption.coDigitAsNumbers]));

        //Сравнение цифр как строки.

        //В результате будет 1 (т.е. строка 1 сортируется после строки 2).

        Writeln(string.Compare(‘2’, ’10’));

        //РегистроНЕзависимое сравнение с определённым языком и регионом. В результате будет 0 (т.е. строки 1 и 2 одинаковые).

        Writeln(string.Compare(‘Арбуз’, ‘арбуз’, true, TLanguages.GetLocaleIDFromLocaleName(‘ru-RU’)));

        //Сравнение двух строк в двух экземплярах класса TStringBuilder (регистрозависимое).

        stringBuilder1 := TStringBuilder.Create(‘Арбуз’);

        try

            stringBuilder2 := TStringBuilder.Create(‘арбуз’);

            try

                //Результат будет FALSE.

                Writeln(stringBuilder1.Equals(stringBuilder2));

                //Результат будет TRUE.

                stringBuilder2.Clear;

                stringBuilder2.Append(‘Арбуз’);

                Writeln(stringBuilder1.Equals(stringBuilder2));

            finally

                stringBuilder2.Free;

            end;

        finally

            stringBuilder1.Free;

        end;

        Readln;

    except

        on E: Exception do

            Writeln(E.ClassName, ‘: ‘, E.Message);

    end;

end.

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

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

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses

    System.SysUtils;

begin

    try

        //Поиск с первого символа. В результате отобразится 8.

        Writeln(Pos(‘строка’, ‘Первая строка, вторая строка’, 1));

        //Поиск с десятого символа. В результате отобразится 23.

        Writeln(Pos(‘строка’, ‘Первая строка, вторая строка’, 10));

        //Поиск несуществующей подстроки. В результате отобразится 0.

        Writeln(Pos(‘третья’, ‘Первая строка, вторая строка’, 1));

        Readln;

    except

        on E: Exception do

            Writeln(E.ClassName, ‘: ‘, E.Message);

    end;

end.

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses

    System.SysUtils;

begin

    try

        //Поиск с начала строки. В результате отобразится 7.

        Writeln(‘Первая строка, вторая строка’.IndexOf(‘строка’));

        //Поиск с десятого символа до конца. В результате отобразится 22.

        Writeln(‘Первая строка, вторая строка’.IndexOf(‘строка’, 9));

        //Поиск несуществующей подстроки. В результате отобразится -1.

        Writeln(‘Первая строка, вторая строка’.IndexOf(‘третья’));

        //Поиск с начала только среди первых 10-ти символов. В результате отобразится -1.

        Writeln(‘Первая строка, вторая строка’.IndexOf(‘строка’, 0, 10));

        //Поиск с начала только среди первых 20-ти символов. В результате отобразится 7.

        Writeln(‘Первая строка, вторая строка’.IndexOf(‘строка’, 0, 20));

        //Поиск с конца строки. В результате отобразится 22.

        Writeln(‘Первая строка, вторая строка’.LastIndexOf(‘строка’));

        //Поиск с двадцать третьего символа и до начала. В результате отобразится 7.

        Writeln(‘Первая строка, вторая строка’.LastIndexOf(‘строка’, 22));

        //Поиск с конца только среди последних 10 символов. В результате отобразится -1.

        Writeln(‘Первая строка, вторая строка, третья’.LastIndexOf(‘строка’, 36, 10));

        //Поиск с конца только среди последних 20 символов. В результате отобразится 22.

        Writeln(‘Первая строка, вторая строка, третья’.LastIndexOf(‘строка’, 36, 20));

        Readln;

    except

        on E: Exception do

            Writeln(E.ClassName, ‘: ‘, E.Message);

    end;

end.

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses

    System.SysUtils, System.StrUtils;

begin

    try

        //В результате отобразится TRUE.

        Writeln(ContainsStr(‘Раз, два, три, четыре, пять’, ‘Раз’));

        //В результате отобразится FALSE.

        Writeln(ContainsStr(‘Раз, два, три, четыре, пять’, ‘Два’));

        //В результате отобразится TRUE.

        Writeln(ContainsText(‘Раз, два, три, четыре, пять’, ‘Три’));

        //В результате отобразится TRUE.

        Writeln(‘Раз, два, три, четыре, пять’.Contains(‘четыре’));

        //В результате отобразится FALSE.

        Writeln(‘Раз, два, три, четыре, пять’.Contains(‘Пять’));

        Readln;

    except

        on E: Exception do

            Writeln(E.ClassName, ‘: ‘, E.Message);

    end;

end.

Дополнительно есть функции проверяющие, наличие определённой подстроки в начале или в конце текста. Это функции 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 ведётся для текущей локали. Т.е. если на компьютере будет установлена английская локаль, то регистронезависимый поиск по русскому тексту работать не будет.

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses

    System.SysUtils, System.StrUtils;

begin

    try

        //Ищем подстроку в начале строки. Результат будет TRUE.

        Writeln(StartsStr(‘Раз’, ‘Раз, два, три’));

        //Ищем подстроку в начале строки. Результат будет FALSE.

        Writeln(StartsStr(‘раз’, ‘Раз, два, три’));

        //Ищем подстроку в начале строки. Результат будет FALSE.

        Writeln(StartsStr(‘два’, ‘Раз, два, три’));

        //Ищем подстроку в начале строки. Результат будет TRUE.

        Writeln(StartsText(‘Раз’, ‘Раз, два, три’));

        //Ищем подстроку в начале строки. Результат будет TRUE.

        Writeln(StartsText(‘раз’, ‘Раз, два, три’));

        //Ищем подстроку в начале строки. Результат будет FALSE.

        Writeln(StartsText(‘два’, ‘Раз, два, три’));

        //Ищем подстроку в начале строки. Результат будет TRUE.

        Writeln(‘Раз, два, три’.StartsWith(‘Раз’));

        //Ищем подстроку в начале строки. Результат будет FALSE.

        Writeln(‘Раз, два, три’.StartsWith(‘раз’));

        //Ищем подстроку в начале строки. Результат будет FALSE (для кириллицы).

        Writeln(‘Раз, два, три’.StartsWith(‘раз’, true));

        //Ищем подстроку в начале строки. Результат будет TRUE (для латиницы).

        Writeln(‘One, two, three’.StartsWith(‘one’, true));

        //Ищем подстроку в начале строки. Результат будет FALSE.

        Writeln(‘Раз, два, три’.StartsWith(‘два’));

        //Ищем подстроку в конце строки. Результат будет TRUE.

        Writeln(EndsStr(‘три’, ‘Раз, два, три’));

        //Ищем подстроку в конце строки. Результат будет FALSE.

        Writeln(EndsStr(‘Три’, ‘Раз, два, три’));

        //Ищем подстроку в конце строки. Результат будет FALSE.

        Writeln(EndsStr(‘два’, ‘Раз, два, три’));

        //Ищем подстроку в конце строки. Результат будет TRUE.

        Writeln(EndsText(‘три’, ‘Раз, два, три’));

        //Ищем подстроку в конце строки. Результат будет TRUE.

        Writeln(EndsText(‘Три’, ‘Раз, два, три’));

        //Ищем подстроку в конце строки. Результат будет FALSE.

        Writeln(EndsText(‘два’, ‘Раз, два, три’));

        //Ищем подстроку в конце строки. Результат будет TRUE.

        Writeln(string.EndsText(‘три’, ‘Раз, два, три’));

        //Ищем подстроку в конце строки. Результат будет TRUE.

        Writeln(string.EndsText(‘Три’, ‘Раз, два, три’));

        //Ищем подстроку в конце строки. Результат будет FALSE.

        Writeln(string.EndsText(‘два’, ‘Раз, два, три’));

        //Ищем подстроку в конце строки. Результат будет TRUE.

        Writeln(‘Раз, два, три’.EndsWith(‘три’));

        //Ищем подстроку в конце строки. Результат будет FALSE.

        Writeln(‘Раз, два, три’.EndsWith(‘Три’));

        //Ищем подстроку в конце строки. Результат будет TRUE.

        Writeln(‘Раз, два, три’.EndsWith(‘Три’, true));

        //Ищем подстроку в конце строки. Результат будет FALSE.

        Writeln(‘Раз, два, три’.EndsWith(‘два’));

        Readln;

    except

        on E: Exception do

            Writeln(E.ClassName, ‘: ‘, E.Message);

    end;

end.

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses

    System.SysUtils, System.RegularExpressions;

var

    regEx: TRegEx;

    match: TMatch;

    matches: TMatchCollection;

begin

    try

        //Ищем в строке любой IP-адрес, с начала строки.

        regEx := TRegEx.Create(‘bd{1,3}.d{1,3}.d{1,3}.d{1,3}b’);

        match := regEx.Match(‘В этой строке два IP-адреса 192.168.1.1 и 192.168.1.15’);

        //Найдена ли подстрока. Результат будет TRUE.

        Writeln(match.Success);

        //Номер первого символа найденной подстроки. Результат будет 29.

        Writeln(match.Index);

        //Длина найденной подстроки. Результат будет 11.

        Writeln(match.Length);

        //Найденная подстрока. Результат будет 192.168.1.1.

        Writeln(match.Value);

        //Ищем следующий IP-адрес в этой же строке.

        match := match.NextMatch;

        //Найдена ли следующая подстрока. Результат будет TRUE.

        Writeln(match.Success);

        //Номер первого символа найденной подстроки. Результат будет 43.

        Writeln(match.Index);

        //Длина найденной подстроки. Результат будет 12.

        Writeln(match.Length);

        //Найденная подстрока. Результат будет 192.168.1.15.

        Writeln(match.Value);

        //Ищем следующий IP-адрес в этой же строке.

        match := match.NextMatch;

        //Найдена ли следующая подстрока. Результат будет FALSE.

        Writeln(match.Success);

        //Ищем адреса почтовых ящиков в тексте, игнорируя регистр.

        regEx := TRegEx.Create(‘b[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,}b’, [roIgnoreCase]);

        matches := regEx.Matches(‘В этой test@example.com строке a.b-93@example.com содержатся три Proghouse@example.com почтовых адреса.’);

        //В результате будет выдано три адреса:

        //test@example.com

        //a.b-93@example.com

        //Proghouse@example.com

        for match in matches do

            Writeln(match.Value);

        Readln;

    except

        on E: Exception do

            Writeln(E.ClassName, ‘: ‘, E.Message);

    end;

end.

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

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

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses

    System.SysUtils, System.StrUtils, Winapi.Windows;

begin

    try

        //Ищем символ ‘р’ или ‘о’. В результате будет 2.

        Writeln(‘Это строка!’.IndexOfAny([‘р’, ‘о’]));

        //Ищем символ ‘р’ или ‘о’ начиная с пятого символа. В результате будет 6.

        Writeln(‘Это строка!’.IndexOfAny([‘р’, ‘о’], 4));

        //Ищем символ ‘р’ или ‘о’ с пятого по шестой символ. В результате будет -1.

        Writeln(‘Это строка!’.IndexOfAny([‘р’, ‘о’], 4, 2));

        //Ищем символ ‘р’ или ‘о’ с конца строки. В результате будет 7.

        Writeln(‘Это строка!’.LastIndexOfAny([‘р’, ‘о’]));

        //Ищем символ ‘р’ или ‘о’ начиная с пятого символа и до начала. В результате будет 2.

        Writeln(‘Это строка!’.LastIndexOfAny([‘р’, ‘о’], 4));

        //Ищем символ ‘р’ или ‘о’ с пятого по третий символ. В результате будет 2.

        Writeln(‘Это строка!’.LastIndexOfAny([‘р’, ‘о’], 4, 3));

        //Ищем символ ‘р’ или ‘о’, но не среди символов заключенных в кавычки. В результате будет 8.

        Writeln(‘”Это” строка!’.IndexOfAnyUnquoted([‘р’, ‘о’], ‘”‘, ‘”‘));

        //Ищем символ ‘р’ или ‘о’, но не среди символов заключенных в скобки, в том числе вложенных. В результате будет 17.

        Writeln(‘(Это (вторая)) строка!’.IndexOfAnyUnquoted([‘р’, ‘о’], ‘(‘, ‘)’));

        Readln;

    except

        on E: Exception do

            Writeln(E.ClassName, ‘: ‘, E.Message);

    end;

end.

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

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses

    System.SysUtils, System.StrUtils, System.RegularExpressions;

var

    stringBuilder: TStringBuilder;

    regEx: TRegEx;

begin

    try

        //Ищет все подстроки в строке и заменяет их на новые (регистрозависимый поиск).

        //В результате будет ‘Раз, два, три, два’.

        Writeln(ReplaceStr(‘Раз, четыре, три, четыре’, ‘четыре’, ‘два’));

        //Ищет все подстроки в строке и заменяет их на новые (регистрозависимый поиск).

        //В результате будет ‘Раз, Четыре, три, два’.

        Writeln(ReplaceStr(‘Раз, Четыре, три, четыре’, ‘четыре’, ‘два’));

        //Ищет все подстроки в строке и заменяет их на новые (регистронезависимый поиск).

        //В результате будет ‘Раз, два, три, два’.

        Writeln(ReplaceText(‘Раз, четыре, три, четыре’, ‘четыре’, ‘два’));

        //Ищет все подстроки в строке и заменяет их на новые (регистронезависимый поиск).

        //В результате будет ‘Раз, два, три, два’.

        Writeln(ReplaceText(‘Раз, Четыре, три, четыре’, ‘четыре’, ‘два’));

        //Ищет только первую подстроку в строке и заменяет её на новую.

        //В результате будет ‘Раз, два, три, четыре’.

        Writeln(StringReplace(‘Раз, четыре, три, четыре’, ‘четыре’, ‘два’, []));

        //Ищет все подстроки в строке и заменяет их на новые.

        //В результате будет ‘Раз, два, три, два’.

        Writeln(StringReplace(‘Раз, четыре, три, четыре’, ‘четыре’, ‘два’, [rfReplaceAll]));

        //Пример регистрозависимого поиска и замены подстрок.

        //В результате будет ‘Раз, Четыре, три, два’.

        Writeln(StringReplace(‘Раз, Четыре, три, четыре’, ‘четыре’, ‘два’, [rfReplaceAll]));

        //Пример регистронезависимого поиска и замены подстрок.

        //В результате будет ‘Раз, два, три, два’.

        Writeln(StringReplace(‘Раз, Четыре, три, четыре’, ‘четыре’, ‘два’, [rfReplaceAll, rfIgnoreCase]));

        //Ищет все подстроки в строке и заменяет их на новые

        //(т.к. по умолчанию установлен флаг rfReplaceAll).

        //В результате будет ‘Раз, два, три, два’.

        Writeln(‘Раз, четыре, три, четыре’.Replace(‘четыре’, ‘два’));

        //Ищет только первую подстроку в строке и заменяет её на новую

        //(т.к нет флага rfReplaceAll).

        //В результате будет ‘Раз, два, три, четыре’.

        Writeln(‘Раз, четыре, три, четыре’.Replace(‘четыре’, ‘два’, []));

        //Пример регистрозависимого поиска и замены подстрок

        //(т.к. по умолчанию не установлен флаг rfIgnoreCase).

        //В результате будет ‘Раз, Четыре, три, два’.

        Writeln(‘Раз, Четыре, три, четыре’.Replace(‘четыре’, ‘два’));

        //Пример регистронезависимого поиска и замены подстрок

        //(т.к. установлен флаг rfIgnoreCase).

        //В результате будет ‘Раз, два, три, четыре’.

        Writeln(‘Раз, Четыре, три, четыре’.Replace(‘четыре’, ‘два’, [rfIgnoreCase]));

        stringBuilder := TStringBuilder.Create;

        try

            //Ищет все подстроки в строке и заменяет их на новые.

            //Результат будет ‘Раз, два, три, два’.

            stringBuilder.Append(‘Раз, четыре, три, четыре’);

            Writeln(stringBuilder.Replace(‘четыре’, ‘два’).ToString);

            //Ищет все подстроки в строке и заменяет их на новые.

            //Результат будет ‘Раз, Четыре, три, два’.

            stringBuilder.Clear;

            stringBuilder.Append(‘Раз, Четыре, три, четыре’);

            Writeln(stringBuilder.Replace(‘четыре’, ‘два’).ToString);

            //Ищет все подстроки начиная с 4-го символа в пределах 10-ти символов и заменяет их на новые.

            //Результат будет ‘Раз, два, три, четыре’.

            stringBuilder.Clear;

            stringBuilder.Append(‘Раз, четыре, три, четыре’);

            Writeln(stringBuilder.Replace(‘четыре’, ‘два’, 3, 10).ToString);

        finally

            stringBuilder.Free;

        end;

        //Ищем и убираем HTML тэги из строки.

        //В результате получится: Здесь содержатся выделенное и подчёркнутое слова и ссылка.

        regEx := TRegEx.Create(‘<([A-Z][A-Z0-9]*)b[^>]*>(.*?)</1>’, [roIgnoreCase]);

        Writeln(regEx.Replace(‘Здесь содержатся <b>выделенное</b> и <u>подчёркнутое</u> слова и <a href=”http://www.proghouse.ru”>ссылка</a>.’, ‘2’));

        //Ищем определённое слово и заменяем его звёздочками.

        //В результате получится: Закрываем *** слова звёздами. *** слов не будет! *** слово – это ***!

        regEx := TRegEx.Create(‘плох[ио][емх]?’, [roIgnoreCase]);

        Writeln(regEx.Replace(‘Закрываем плохие слова звёздами. Плохих слов не будет! Плохое слово – это плохо!’, ‘***’));

        Readln;

    except

        on E: Exception do

            Writeln(E.ClassName, ‘: ‘, E.Message);

    end;

end.

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

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses

    System.SysUtils;

begin

    try

        //Удаляем пробелы и управляющие символы в начале и конце строки.

        //Результат будет ‘Строка без лишних пробелов и управляющих символов!’.

        Writeln(Trim(#13#10′ Строка без лишних пробелов и управляющих символов! ‘#13#10));

        //Удаляем пробелы и управляющие символы в начале и конце строки.

        //Результат будет ‘Строка без лишних пробелов и управляющих символов!’.

        Writeln(#13#10′ Строка без лишних пробелов и управляющих символов! ‘#13#10.Trim);

        //Удаляем только символы #13 и #10 в начале и конце строки.

        //Результат будет ‘ Строка без лишних пробелов и управляющих символов! ‘.

        Writeln(#13#10′ Строка без лишних пробелов и управляющих символов! ‘#13#10.Trim([#13, #10]));

        //Удаляем пробелы и управляющие символы только в начале строки.

        //Результат будет ‘Строка без лишних пробелов и управляющих символов! ‘#13#10.

        Writeln(TrimLeft(#13#10′ Строка без лишних пробелов и управляющих символов! ‘#13#10));

        //Удаляем пробелы и управляющие символы только в начале строки.

        //Результат будет ‘Строка без лишних пробелов и управляющих символов! ‘#13#10.

        Writeln(#13#10′ Строка без лишних пробелов и управляющих символов! ‘#13#10.TrimLeft);

        //Удаляем пробелы и управляющие символы только в конце строки.

        //Результат будет #13#10′ Строка без лишних пробелов и управляющих символов!’.

        Writeln(TrimRight(#13#10′ Строка без лишних пробелов и управляющих символов! ‘#13#10));

        //Удаляем пробелы и управляющие символы только в конце строки.

        //Результат будет #13#10′ Строка без лишних пробелов и управляющих символов!’.

        Writeln(#13#10′ Строка без лишних пробелов и управляющих символов! ‘#13#10.TrimRight);

        Readln;

    except

        on E: Exception do

            Writeln(E.ClassName, ‘: ‘, E.Message);

    end;

end.

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

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses

    System.SysUtils;

begin

    try

        //Дополняем числа пробелами. В результате получится:

        //’  123′

        //’12345′

        //’ 1234′

        Writeln(‘123’.PadLeft(5));

        Writeln(‘12345’.PadLeft(5));

        Writeln(‘1234’.PadLeft(5));

        //Дополняем числа нулями. В результате получится.

        //’00123′

        //’12345′

        //’01234′

        Writeln(‘123’.PadLeft(5, ‘0’));

        Writeln(‘12345’.PadLeft(5, ‘0’));

        Writeln(‘1234’.PadLeft(5, ‘0’));

        //Дополняем строки чёрточками, чтобы сделать красивое содержание.

        //В результате получится:

        //’Вступление ——— стр. 1′

        //’Доклад ————- стр. 2′

        //’Выводы ————- стр. 7′

        //’Заключение ——— стр. 9′

        Writeln(‘Вступление ‘.PadRight(20, ‘-‘) + ‘ стр. 1’);

        Writeln(‘Доклад ‘.PadRight(20, ‘-‘) + ‘ стр. 2’);

        Writeln(‘Выводы ‘.PadRight(20, ‘-‘) + ‘ стр. 7’);

        Writeln(‘Заключение ‘.PadRight(20, ‘-‘) + ‘ стр. 9’);

        Readln;

    except

        on E: Exception do

            Writeln(E.ClassName, ‘: ‘, E.Message);

    end;

end.

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

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

Метки: Delphi, striing

Опубликовано 30.01.2017 от evgeniyalf в категории “Delphi

Добавить комментарий