Работа со строками [Функции]

Предисловие:
Довайте с вами рассмотрим основные функции для работы со строками, вообще в свободное время мне
нравиться помудиться со строками- пропарсить какойлибо сайт и тд: наша цель, пропарсить сайт
_http://myip.ru и добыть наш ип в удобной форме x) Хотя легче конечно залезть на сам сайт и посмотреть
НО представим что ип нам нужно вывести в своей проге или отправить на мыло- конечно узнать ип можно
поразному, но мы выберем именно этот способ

Наконец-то расшифрована звукозапись первого полета в космос Ю.Гагарина:
Эй... Куда вы меня тащите...Эээ... Вы что?... Что это за хреновина? У вас что у всех крыши ПОЕХАЛИ...
Вот и мы...

Поехали
Наши строковые функции:


Length(Str: String)   
SetLength(Str: String; NewLength: Integer)   
Pos(SubStr, Str: String)   
PosEx(SubStr, Str: String; Offset: Integer)   
Delete(Str: String; Start, Length: Integer)    
Copy(Str: String; Start, Length: Integer)    
LowerCase(Str: String)    
UpperCase(Str: String)    
AnsiReplaceStr(Str, FromText, ToText: String)    
AnsiReplaceText(Str, FromText, ToText: String)   
ReverseString(Str: String)    
AnsiReverseString(Str: AnsiString)    
DupeString(Str: String; Count: Integer)  

Для выполнения поставленной задачи "Добыть IP" нам потребуються не все из них- но всё же рассмотрим
их все. Так- начнём попорядку:


//////LENGTH//////   
Length(Str: String)  

Дання функция возврощает колличество символов в строке.
Пример:


len:=length('hallо world')   

дання строка возвратит нам число 11, как видим значение которое вернула функция поместиться в
переменную len, для примера- чтобы посмотреть результат напишем showmessage(len);


len:=length('hellо world');   
showmessage(len);   
--- 
Результат "11" 
---



//////SetLength//////   
SetLength(Str: String; NewLength: Integer)   

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


len:='строка для примера';   
len:=setlength(len,6);   
showmessage(str);   
--- 
Результат "строка" 
---



//////Pos//////   
Pos(SubStr, Str: String)   

Данная функция ищет вхождение подстроки
Пример:


len:='login@mail.ru';   
num:=pos('@', len);  
showmessage(inttostr(num));   
--- 
Результат "6" 
---



//////PosEx//////   
PosEx
(SubStr, Str: String; Offset: Integer) [/DELPHI]
Для того чтобы работать с этой функцией подключети в uses "StrUtils".
Данная фукнция аналогична функции Pos с той лишь разницей что можно указать отступ, тобиш с какого
символа будет начат поиск подстроки
Пример:


len1:='Что за тупая функция';   
len2:='тупая';  
num1:=PosEx(len2, len1, 2);   
num1:=PosEx(len2, len1, 3);  
showmessage(inttostr(P1));   
showmessage(inttostr(P2));   
--- 
Результат "3" и "4" 
---



//////Delete//////   
Delete(Str: String; Start, Length: Integer)   

Функция удаляет часть строки...
Пример:


len:='Дарова Ping0, опять нажрался?';   
Delete(len, 13, 17);   
showmessage(len);  
--- 
Результат "Дарова Ping0" 
---



//////Copy////// Copy(Str: String; Start, Length: Integer)   

Данная функция копирует часть строки
Пример:


len:='Дарова Ping0, опять нажрался?';   
len:=copy(len, 15, 15);   
showmessage(len);   
--- 
Результат "опять нажрался?" 
---



//////LowerCase//////   
LowerCase(Str: String)   

Данная функция преобразует строку в нижний регистор
Пример:


len:=lowercase'I HeKeR pOetOmU nEpishU ZaborChiKoM';   
showmessage(len);   
--- 
Результат "i heker poetomu nepishu zaborchikom" 
---


жаль что данная функци я никак нереагирует на русские буквы =(


//////UpperCase//////   
UpperCase(Str: String)   

Данная функция аналогично функции LowerCase с той лиш разницей что преобразует текст в верхний
регистор, думаю приводить пример ненадо )


//////AnsiReplaceStr//////   
AnsiReplaceStr(Str, FromText, ToText: String)   

Опять же чтобы работала данная функция нцжно подключить в uses "StrUtils".
Пример:


len:='Всем Привет';   
len2:=AnsiReplaceStr(Str1, 'Привет', 'пока');   
showmessage(str2)   
--- 
Результат "Всем пока" 
---



//////AnsiReplaceText//////   
AnsiReplaceText(Str, FromText, ToText: String)   

Опять же незабываем подключить в uses "StrUtils".
Функция аналогична предыдущий функции "AnsiReplaceStr" с той лишь разницей что она независима от регистра.
Пример:


len:='Всем Привет';   
len2:=AnsiReplaceStr(Str1, 'ПриВеТ', 'пока');   
showmessage(str2)   
--- 
Результат "Всем пока" 
---



//////ReverseString//////   
ReverseString(Str: String)   

Незабываем подключить в uses "StrUtils".
Функция моя самая любимая ) Она позволяет перевернуть строку
Пример:


len:='Всем привет';   
len:=reversestring(len);   
showmessage(len)   
--- 
Результат "акоп месВ" 
---



//////AnsiReverseString//////   
AnsiReverseString(Str: AnsiString)   

Аналогична функции ReverseString


//////DupeString//////   

DupeString(Str: String; Count: Integer)
Интересная функция однако, копирует строку столько раз сколько указанно в аргументе Count
Пример:


len:='Всем привет';   
len:=dupestring(len,5);   
showmessage(len)   
--- 
Результат "Всем приветВсем приветВсем приветВсем приветВсем привет" 
---


С функциями всё- теперь довайте для приличия всёже получим этот ИП "млять, только теперь я понимаю-
что этот долбанный ип нестоил столько моего времени, которое я потратил на написание статьи )"
Кидаем на форму IdHTTP, Memo и Button
и в обработчие собития OnClick у кнопки, пишем:
Код:


var len:string; num:integer;   
begin memo1.text:=idhttp1.get('http://www.myi p.ru/get_ip.php');  
len:=memo1.text;   
num:=pos('<TD bgcolor=white align=center v align=middle>',len) +45;   
delete(len,1,num);   
len:=copy(memo1.text, num, pos('<',len)) ;   
memo1.Text:=len;   

Жмёте кнопку и получаете ип..
Ну вот впринципе и всё!
Всем спасибо за внимание- надеюсь кому пригодиться

Добавлено: 07 Августа 2018 21:09:45 Добавил: Андрей Ковальчук

Работа со строковыми типами данных

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

Юникод-символы - многопользовательские сервера, мультиязыковые приложения

Для большинства целей подходит тип AnsiString (иногда называется Long String).

Стандартные функции обработки строк:

1) Функция Length(Str: String) - возвращает длину строки (количество символов). Пример:


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

2) Функция SetLength(Str: String; NewLength: Integer) позволяет изменить длину строки. Если строка содержала большее количество символов, чем задано в функции, то "лишние" символы обрезаются. Пример:


var Str: String;  
{ ... }  
Str:='Hello, world!';  
SetLength(Str, 5); { Str = "Hello" }  

3) Функция Pos(SubStr, Str: String) - возвращает позицию подстроки в строке. Нумерация символов начинается с единицы (1). В случае отсутствия подстроки в строке возращается 0. Пример:


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

4) Функция Copy(Str: String; Start, Length: Integer) - возвращает часть строки Str, начиная с символа Start длиной Length. Ограничений на Length нет - если оно превышает количество символов от Start до конца строки, то строка будет скопирована до конца. Пример:


var Str1, Str2: String;  
{ ... }  
Str1:='This is a test for Copy() function.';  
Str2:=Copy(Str1, 11, 4); { Str2 = "test" }  

5) Процедура Delete(Str: String; Start, Length: Integer) - удаляет из строки Str символы, начиная с позиции Start длиной Length. Пример:


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

6) Процедура Insert(SubStr: String; Str: String; Pos: Integer) - вставляет в строку Str подстроку SubStr в позицию Pos. Пример:


var Str: String;  
{ ... }  
Str:='Hello, world!';  
Insert('my ',Str, 8); { Str1 = "Hello, my world!" }  

7) Функции UpperCase(Str: String) и LowerCase(Str: String) преобразуют строку соответственно в верхний и нижний регистры:


var Str1, Str2, Str3: String;  
{ ... }  
Str1:='hELLo';  
Str2:=UpperCase(Str1); { Str2 = "HELLO" }  
Str3:=LowerCase(Str1); { Str3 = "hello" }  

Строки можно сравнивать друг с другом стандартным способом:


var Str1, Str2, Str3: String; B1, B2: Boolean;  
{ ... }  
Str1:='123';  
Str2:='456';  
Str3:='123';  
B1:=(Str1 = Str2); { B1 = False }  
B2:=(Str1 = Str3); { B2 = True }  

Если строки полностью идентичны, логическое выражение станет равным True.

Дополнительные функции обработки строк:

В модуле StrUtils.pas содержатся полезные функции для обработки строковых переменных. Чтобы подключить этот модуль к программе, нужно добавить его имя (StrUtils) в раздел Uses.

1) PosEx(SubStr, Str: String; Offset: Integer) - функция аналогична функции Pos(), но позволяет задать отступ от начала строки для поиска. Если значение Offset задано (оно не является обязательным), то поиск начинается с символа Offset в строке. Если Offset больше длины строки Str, то функция возратит 0. Также 0 возвращается, если подстрока не найдена в строке. Пример:


uses StrUtils;  
{ ... }  
var Str1, Str2: String; P1, P2: Integer;  
{ ... }  
Str1:='Hello! How do you do?';  
Str2:='do';  
P1:=PosEx(Str2, Str1, 1); { P1 = 12 }  
P2:=PosEx(Str2, Str1, 15); { P2 = 19 }  

2) Функция AnsiReplaceStr(Str, FromText, ToText: String) - производит замену выражения FromText на выражение ToText в строке Str. Поиск осуществляется с учётом регистра символов. Следует учитывать, что функция НЕ изменяет самой строки Str, а только возвращает строку с произведёнными заменами. Пример:


uses StrUtils;  
{ ... }  
var Str1, Str2, Str3, Str4: String;  
{ ... }  
Str1:='ABCabcAaBbCc';  
Str2:='abc';  
Str3:='123';  
Str4:=AnsiReplaceStr(Str1, Str2, Str3); { Str4 = "ABC123AaBbCc" }  

3) Функция AnsiReplaceText(Str, FromText, ToText: String) - выполняет то же самое действие, что и AnsiReplaceStr(), но с одним исключением - замена производится без учёта регистра. Пример:


uses StrUtils;  
{ ... }  
var Str1, Str2, Str3, Str4: String;  
{ ... }  
Str1:='ABCabcAaBbCc';  
Str2:='abc';  
Str3:='123';  
Str4:=AnsiReplaceText(Str1, Str2, Str3); { Str4 = "123123AaBbCc" }  

4) Функция DupeString(Str: String; Count: Integer) - возвращает строку, образовавшуюся из строки Str её копированием Count раз. Пример:


uses StrUtils;  
{ ... }  
var Str1, Str2: String;  
{ ... }  
Str1:='123';  
Str2:=DupeString(Str1, 5); { Str2 = "123123123123123" }  

5) Функции ReverseString(Str: String) и AnsiReverseString(Str: AnsiString) - инвертируют строку, т.е. располагают её символы в обратном порядке. Пример:


uses StrUtils;  
{ ... }  
var Str1: String;  
{ ... }  
Str1:='0123456789';  
Str1:=ReverseString(Str1); { Str1 = "9876543210" }  

6) Функция IfThen(Value: Boolean; ATrue, AFalse: String) - возвращает строку ATrue, если Value = True и строку AFalse если Value = False. Параметр AFalse является необязательным - в случае его отсутствия возвращается пустая строка.


uses StrUtils;  
{ ... }  
var Str1, Str2: String;  
{ ... }  
Str1:=IfThen(True, 'Yes'); { Str1 = "Yes" }  
Str2:=IfThen(False, 'Yes', 'No'); { Str2 = "No" }  

Мы рассмотрели функции, позволяющие выполнять со строками практически любые манипуляции. Как правило, вместо строки с указанным типом данных, можно использовать и другой тип - всё воспринимается одинаково. Но иногда требуются преобразования. Например, многие методы компонент требуют параметр типа PChar, получить который можно из обычного типа String функцией PChar(Str: String):


uses ShellAPI;  
{ ... }  
var FileName: String;  
{ ... }  
FileName:='C:\WINDOWS\notepad.exe';  
ShellExecute(0, 'open', PChar(FileName), '', '', SW_SHOWNORMAL);  

Тип Char представляет собой один-единственный символ. Работать с ним можно как и со строковым типом. Для работы с символами также существует несколько функций:

Chr(Code: Byte) - возвращает символ с указанным кодом (по стандарту ASCII):


var A: Char;  
{ ... }  
A:=Chr(69); { A = "E" }  

Ord(X: Ordinal) - возвращает код указанного символа, т.е. выполняет противоположное действие функции Chr():


var X: Integer;  
{ ... }  
X:=Ord('F'); { X = 70 }  

Из строки можно получить любой её символ - следует рассматривать строку как массив. Например:


var Str, S: String; P: Char;  
{ ... }  
Str:='Hello!';  
S:=Str[2]; { S = "e" }  
P:=Str[5]; { P = "o" }  

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

Добавлено: 07 Августа 2018 08:30:48 Добавил: Андрей Ковальчук

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

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

Символы
Символ - это одна единица текста. Это буква, цифра, какой-либо знак. Кодовая таблица символов состоит из 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[10];  

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

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


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.

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

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


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

Заключение
Длинный получился урок... И как раз афоризм оказался в тему. Что удивительно, афоризм был подобран мной в самом начале, а сам урок написан позже :-)

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

Автор: © Ерёмин А.А., 2008

Добавлено: 04 Августа 2018 14:39:32 Добавил: Андрей Ковальчук

Полезные функции работы со строками

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

Перейдем от слов к делу, надо уже скорее знакомить Вас с этими функциями! Первая, которую я предложу Вам проверяет есть ли подстрока в строке, и если есть - возвращает true, иначе - false.

Функция эта выглядит так:


function MatchStrings(source, pattern: String): Boolean;  
var  
  
pSource: Array [0..255] of Char;  
pPattern: Array [0..255] of Char;  
  
  
function MatchPattern(element, pattern: PChar): Boolean;  
  
  
function IsPatternWild(pattern: PChar): Boolean;  
var  
t: Integer;  
begin  
Result := StrScan(pattern,'*') <> nil;  
if not Result then Result := StrScan(pattern,'?') <> nil;  
end;  
  
  
begin  
if 0 = StrComp(pattern,'*') then  
Result := True  
else if (element^ = Chr(0)) and (pattern^ <> Chr(0)) then  
Result := False  
else if element^ = Chr(0) then  
Result := True  
else begin  
case pattern^ of  
'*': if MatchPattern(element,@pattern[1]) then  
Result := True  
else  
Result := MatchPattern(@element[1],pattern);  
'?': Result := MatchPattern(@element[1],@pattern[1]);  
else  
if element^ = pattern^ then  
Result := MatchPattern(@element[1],@pattern[1])  
else  
Result := False;  
end;  
end;  
end;  
  
begin  
  
StrPCopy(pSource,source);  
StrPCopy(pPattern,pattern);  
Result := MatchPattern(pSource,pPattern);  
end;  

Использовать ее нужно примерно так:


MatchStrings('Михаил' , '*' + 'Михаил автор данной статьи' + '*');  

Вызов этой функции в данном примере возвратит true, так как строка 'Михаил' содержится в строке 'Михаил автор этой статьи'. Символы '*' нужны для корректности работы функции. Разберем небольшой пример, будем вводить текст в поле Edit1, и искать его в Memo1, по нажатию на командной кнопке Button1. Итак, разместим перечисленные компоненты на форме. Скопируйте описание функции и поместите его после


implementation  
  
{$R *.DFM}  
А обработчик нажатия на командную кнопку может иметь такой вид:


procedure TForm1.Button1Click(Sender: TObject);  
var i:integer;  
n_sov:integer;//число совпадений  
begin  
n_sov:=0;  
for i:= 0 to memo1.Lines.Count-1 do  
begin  
if matchstrings(memo1.lines[i],'*'+edit1.text+'*') = true then  
inc(n_sov) else;  
end;  
showmessage(inttostr(n_sov));  
end;  
На всякий случай :) приведу полный код примера:


unit Unit1;  
  
interface  
  
uses  
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,  
StdCtrls;  
  
type  
TForm1 = class(TForm)  
Memo1: TMemo;  
Edit1: TEdit;  
Button1: TButton;  
procedure Button1Click(Sender: TObject);  
private  
{ Private declarations }  
public  
{ Public declarations }  
end;  
  
var  
Form1: TForm1;  
  
implementation  
  
{$R *.DFM}  
  
function MatchStrings(source, pattern: String): Boolean;  
var  
  
pSource: Array [0..255] of Char;  
pPattern: Array [0..255] of Char;  
  
  
function MatchPattern(element, pattern: PChar): Boolean;  
  
  
function IsPatternWild(pattern: PChar): Boolean;  
var  
t: Integer;  
begin  
Result := StrScan(pattern,'*') <> nil;  
if not Result then Result := StrScan(pattern,'?') <> nil;  
end;  
  
  
begin  
if 0 = StrComp(pattern,'*') then  
Result := True  
else if (element^ = Chr(0)) and (pattern^ <> Chr(0)) then  
Result := False  
else if element^ = Chr(0) then  
Result := True  
else begin  
case pattern^ of  
'*': if MatchPattern(element,@pattern[1]) then  
Result := True  
else  
Result := MatchPattern(@element[1],pattern);  
'?': Result := MatchPattern(@element[1],@pattern[1]);  
else  
if element^ = pattern^ then  
Result := MatchPattern(@element[1],@pattern[1])  
else  
Result := False;  
end;  
end;  
end;  
begin  
  
StrPCopy(pSource,source);  
StrPCopy(pPattern,pattern);  
Result := MatchPattern(pSource,pPattern);  
end;  
  
procedure TForm1.Button1Click(Sender: TObject);  
var i:integer;  
n_sov:integer;//число совпадений  
begin  
n_sov:=0;  
for i:= 0 to memo1.Lines.Count-1 do  
begin  
if matchstrings(memo1.lines[i],'*'+edit1.text+'*') = true then  
inc(n_sov) else;  
end;  
showmessage(inttostr(n_sov));  
end;  
  
end.  

Если вдруг кто-то не знает, то функция inc(x:ordinal); увеличивает число на единицу (а функция Dec - уменьшает). Таким образом мы просто проходим в цикле все строки Memo1 и ищем совпадения. К сожалению эта функция умеет только указывать если подстрока в строке, но неплохо было бы ее доработать, чтобы она возвращала позицию символа, с которого начинается совпадение. Если у вас есть идеи, то пожалуйста пишите!

Теперь познакомимся с более интересной функцией, которая заменяет одну подстроку на другую в строке. Она выглядит таким образом:


function ReplaceSub(str, sub1, sub2: String): String;  
var  
aPos: Integer;  
rslt: String;  
begin  
aPos := Pos(sub1, str);  
rslt := '';  
while (aPos <> 0) do begin  
rslt := rslt + Copy(str, 1, aPos - 1) + sub2;  
Delete(str, 1, aPos + Length(sub1) - 1);  
aPos := Pos(sub1, str);  
end;  
Result := rslt + str;  
end;  

Эта функция заменяет Sub1 на Sub2 в строке Str и возвращает измененную строку.

Сразу усовершенствуем наш пример, дабы разобраться с использованием этой функции. Добавьте на форму еще одно текстовое поле Edit2. В Edit1 будем вводить слово, которое надо заменить, а в поле Edit2 слово, на которое надо заменить.

Теперь обработчик нажатия на кнопку у меня выглядит так:


procedure TForm1.Button1Click(Sender: TObject);  
var i:integer;  
n_sov:integer;  
begin  
n_sov:=0;  
for i:= 0 to memo1.Lines.Count-1 do  
begin  
if matchstrings(memo1.lines[i],'*' +edit1.text+ '*') = true  
    then begin  
    Memo1.lines[i]:=ReplaceSub(memo1.lines[i],edit1.text,edit2.text);  
    inc(n_sov);  
    end;  
end;  
showmessage(inttostr(n_sov));  
end;  

Ну и опять, на всякий случай, приведу полный код примера:


unit Unit1;  
  
interface  
  
uses  
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,  
StdCtrls;  
  
type  
TForm1 = class(TForm)  
Memo1: TMemo;  
Edit1: TEdit;  
Button1: TButton;  
Edit2: TEdit;  
procedure Button1Click(Sender: TObject);  
private  
{ Private declarations }  
public  
{ Public declarations }  
end;  
  
var  
Form1: TForm1;  
  
implementation  
  
{$R *.DFM}  
  
function MatchStrings(source, pattern: String): Boolean;  
var  
  
pSource: Array [0..255] of Char;  
pPattern: Array [0..255] of Char;  
  
  
function MatchPattern(element, pattern: PChar): Boolean;  
  
  
function IsPatternWild(pattern: PChar): Boolean;  
var  
t: Integer;  
begin  
Result := StrScan(pattern,'*') <> nil;  
if not Result then Result := StrScan(pattern,'?') <> nil;  
end;  
  
  
begin  
if 0 = StrComp(pattern,'*') then  
Result := True  
else if (element^ = Chr(0)) and (pattern^ <> Chr(0)) then  
Result := False  
else if element^ = Chr(0) then  
Result := True  
else begin  
case pattern^ of  
'*': if MatchPattern(element,@pattern[1]) then  
Result := True  
else  
Result := MatchPattern(@element[1],pattern);  
'?': Result := MatchPattern(@element[1],@pattern[1]);  
else  
if element^ = pattern^ then  
Result := MatchPattern(@element[1],@pattern[1])  
else  
Result := False;  
end;  
end;  
end;  
begin  
  
StrPCopy(pSource,source);  
StrPCopy(pPattern,pattern);  
Result := MatchPattern(pSource,pPattern);  
end;  
  
function ReplaceSub(str, sub1, sub2: String): String;  
var  
aPos: Integer;  
rslt: String;  
begin  
aPos := Pos(sub1, str);  
rslt := '';  
while (aPos <> 0) do begin  
rslt := rslt + Copy(str, 1, aPos - 1) + sub2;  
Delete(str, 1, aPos + Length(sub1) - 1);  
aPos := Pos(sub1, str);  
end;  
Result := rslt + str;  
end;  
  
  
procedure TForm1.Button1Click(Sender: TObject);  
var i:integer;  
n_sov:integer;  
begin  
n_sov:=0;  
for i:= 0 to memo1.Lines.Count-1 do  
begin  
if matchstrings(memo1.lines[i],'*' +edit1.text+ '*') = true  
then begin  
Memo1.lines[i]:=ReplaceSub(memo1.lines[i],edit1.text,edit2.text);  
inc(n_sov);  
end;  
end;  
showmessage(inttostr(n_sov));  
end;  
  
end.  

На этом пока все. Надеюсь сумело помочь Вам в Ваших начинаниях

Добавлено: 04 Августа 2018 08:40:01 Добавил: Андрей Ковальчук

Бегущий текст

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

Итак, создаем новый Delphi проект. Переходим в окно кода, и после ключевого слова var дописываем:


bm:TBitmap;x,y:Integer;  

Потом опять, переходим на форму, и кидаем компонент TTimer (вкладка system). Свойство Enabled ставим в значение false, а в свойстве interval таймера ставим значение 20.
Далее, создаем обработчик событий OnCreate на форме. В котором прописываем следующий код:


x:=Form1.width/2; //текст будет выводиться посредине формы  
y:=Height+50; //чтобы текст выводился не сразу  
bm:=TBitmap.Create; //создаем объект TBitmap  
bm.Width:=width; //ширина как у формы  
bm.height:=height; //высота как у формы  
bm.PixelFormat:=pf32bit; //32 битный режим изображения  
Canvas.Font.Name:='Times New Roman'; //делаем шрифт Times New Roman  
bm.Canvas.Brush.Color:= $004F4F52; //серый цвет фона bitmap  
bm.Canvas.FillRect(bm.Canvas.ClipRect); //делаем, bitmap стал весь серый  
timer1.Enabled:=True; //включаем таймер  

Далее создаем, обработчик событий OnTimer у таймера и пишем туда следующий код:

y:=y-1;  
if y=-200 then y:=height+10;  
with bm do begin  
Canvas.Font.Color:=$000576DC; //делаем цвет оранжевым  
Canvas.TextOut(x-10,y, 'Имя программы:');  
Canvas.Font.Color:=clWhite;  
Canvas.TextOut(x,y+15, 'Автор: Имя Автора');  
Canvas.Font.Color:=$000576DC; //делаем цвет оранжевым  
Canvas.TextOut(x-10,y+30,'Тестеры:                  ');  
Canvas.Font.Color:=clWhite;  
Canvas.TextOut(x,y+45,'Имя тестера');  
Canvas.TextOut(x,y+60,'Имя тестера');  
Canvas.TextOut(x,y+75,'Имя тестера');  
Canvas.Font.Color:=$000576DC; //делаем цвет оранжевым  
Canvas.TextOut(x-10,y+90,'Спасибо:            ');  
Canvas.Font.Color:=clWhite;  
Canvas.TextOut(x,y+105,'Имя');  
Canvas.TextOut(x,y+120,'Имя');  
Canvas.TextOut(x,y+135,'Имя');  
Canvas.TextOut(x,y+150,'Имя');  
Canvas.Font.Color:=$000576DC; //делаем цвет оранжевым  
Canvas.TextOut(x-10,y+165,'Автор.Год');  
Canvas.TextOut(x-10,y+180,'          ');  
end;  
Canvas.Draw(0,0,bm); //вырисовываем на форме объект Bitmap  

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


if y=-200 then y:=height+10;  

это означает, что если текст вышел вверх на высоту -200 пикселей, то значение y будет высота формы+10, чтобы текст опять ехал вверх.

Добавлено: 01 Августа 2018 07:12:33 Добавил: Андрей Ковальчук

Что такое #13#10?

Несомненно, вы много раз видели в Delphi-коде нечто "#13#10". Если вы не знаете, что это такое и каждый раз удивляетесь, то здесь вы узнаете ответ.

Тип данных string представляет собой совокупность одного или нескольких символов, каждый из которых записывается в виде символа "#" и числа от 0 до 255 (в десятичной или шестнадцатеричной форме) - каждая такая комбинация обозначает соответствующий ASCII-символ.

К примеру, если вы хотите сделать текст (Caption) элемента TLabel в две строки, то это можно сделать следующим образом:


Label1.Caption := 'Первая строка' + #13#10 + 'Вторая строка';  

Комбинация "#13#10" - это комбинация возврата каретки и символа новой строки. "#13" - это ASCII-эквивалент значения CR (carriage return - возврат каретки); "#10" представляет собой LF (line feed - признак новой строки).

Также наиболее интересными управляющими символами являются:
#0 - NULL-символ (нулевой);
#9 - <Tab> (символ табуляции).

Добавлено: 01 Августа 2018 06:54:54 Добавил: Андрей Ковальчук

Поиск в Memo

В этом маленьком уроке я покажу вам как осуществить поиск текста в компоненте MEMO. Давайте откроем Delphi и создадим новый проект, кидаем на форму компонент Edit, Memo, Button все они с закладки Standart. Отлично, идем дальше, в обработчике OnClick кнопки прописываем следующий код:


procedure TForm1.Button1Click(Sender: TObject);  
var // Объявляем переменные  
Find:string; // Искомая строка  
i:integer; // Счетчик для цикла  
begin  
find:=Edit1.Text; // Записываем в find текст из Edit  
For i:=0 to Memo1.Lines.Count-1 do // Запускаем цикл поиска строки  
If Pos(FIND, Memo1.Lines.Text)<>0  
Then  
Begin  
Memo1.SetFocus();  
Memo1.SelStart:=Pos(FIND,Memo1.Lines.Text)-1;  
Memo1.SelLength:=Length(FIND);  
End;  
end;  

Программа будет искать в Memo текст введенный в Edit и если найдет выделит его. Довольно просто и понятно.

Добавлено: 31 Июля 2018 21:56:43 Добавил: Андрей Ковальчук

Как выдать текст под наклоном?

Чтобы вывести под любым углом текст необходимо использовать TrueType Fonts (например "Arial"). Например:


var   
  LogFont : TLogFont;  
...  
  GetObject(Canvas.Font.Handle, SizeOf(TLogFont), @LogFont);  
  { Вывести текст 1/10 градуса против часовой стрелки }  
  LogFont.lfEscapement := Angle*10;   
  Canvas.Font.Handle := CreateFontIndirect(LogFont);

Добавлено: 31 Июля 2018 21:20:16 Добавил: Андрей Ковальчук

Как сделать отступ в Memo?

С помощью API-функции SendMessage можно задать поля в Memo-компоненте. Если необходимо, например, сделать отступ в 20 пикселей слева то можно это сделать следующим образом:


var Rect: TRect;  
begin  
  SendMessage( Memo1.Handle, EM_GETRECT, 0, LongInt(@Rect));  
  Rect.Left:= 20;  
  SendMessage(Memo1.Handle, EM_SETRECT, 0, LongInt(@Rect));  
  Memo1.Refresh;  
end; 

Добавлено: 31 Июля 2018 21:18:57 Добавил: Андрей Ковальчук