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

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

Символы

Символ - это одна единица текста. Это буква, цифра, какой-либо знак. Кодовая таблица символов состоит из 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 используются одинарные кавычки (не двойные!). Т.е. когда вы хотите присвоить строковой переменной какое-либо значение, следует сделать это так:

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

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

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

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

var s: string; c: char; ... s:="Hello!"; c:=s; //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), в который будет введено предложение. Операцию будет выполнять по нажатию на кнопку. Имеем:

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

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

Если требуется в имеющуюся строку вставить другую строку, можно использовать процедуру 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:

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; if Pos(Text[i],DelSym) > 0 then Text[i]:=","; Memo2.Text:=Text; end;

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

if Text = "," then Delete(Text,1,1); while Pos(",",Text) > if Text <> "," then Text:=Text+",";

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

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

var Word: string; {...}

Теперь в переменной 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 = "," 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.

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

Почему цикл до 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 = "," 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; 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[номер_столбца,номер_строки]. В квадратных скобках указываются номера столбца и строки (начинаются с нуля). Значения текстовые.

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

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

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

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

Здесь мы выводим окошко с текстом. У события есть переменная 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.

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

Заключение

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

Министерство образования и науки Российской Федерации

Федеральное агентство по образованию

Саратовский государственный технический университет

Балаковский институт техники, технологии и управления

Работа с символами и строками в языке программирования си

Методические указания к выполнению лабораторной работы по курсу «Логическое программирование» для студентов специальности 071900 дневной формы обучения

Одобрено

редакционно-издательским советом

Балаковского института техники,

технологии и управления

Балаково 2009

ЦЕЛЬ РАБОТЫ : познакомиться с понятиями символьной, строковой переменной, строковой константы, указателя на строки, научиться выполнять операции ввода/вывода строк, определять специфику работы со строковыми функциями.

1. Общие понятия

В данной работе рассматриваются символьные переменные, строковые переменные и константы, операции ввода/вывода строк, основные функции работы со строками.

1.1. Символьные переменные

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

    как целое число, занимающее 1 байт и способное принимать значения:

    • от 0 до 255 (тип unsigned char );

      от -128 до 127 (тип signed char );

    как один текстовый символ.

Сам же тип char может оказаться как знаковым, так и беззнаковым, в зависимости от операционной системы и компилятора. Поэтому использовать тип char не рекомендуется, лучше явно указывать, будет ли он знаковым (signed ) или беззнаковым (unsigned ).

Как и целые числа, данные типа char можно складывать, вычитать, умножать, делить, а можно выводить на экран в виде одного символа.

Если нужно вывести числовое значение символа, также называемое ASCII-кодом, то значение символа необходимо преобразовать к типу int . Например:

#include

using namespace std;

unsigned char c="A"; // Константы char заключаются в одинарные кавычки

cout<

c=126; // char можно присвоить и числовое значение

cout<

В этом примере переменной с типа char присваивается значение, равное символу "A" (константы типа char записываются как символы в одинарных кавычках), затем на экран выводится значение c как символа и его ASCII-код, потом переменной c присваивается значение 126, то есть символ с ASCII-кодом 126 и снова выводится на экран символ и его ASCII-код.

1.2. Строковые переменные и константы

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

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

Строковые переменные должны быть объявлены перед тем, как начнется их использование. Объявление строковой переменной выглядит следующим образом: char s,

где s рассматривается как массив с элементами символьного типа, который может содержать до 14 элементов. Предположим, что s присваивается строковая константа:

Я ПРОГРАММИСТ!

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

Символ ‘\0’ нуль (null) – символ автоматически добавляется к внутрисистемному представлению строки для того, чтобы в программе можно было определить конец строки. Таким образом, при описании строковой переменной следует предусматривать один дополнительный элемент для завершающего нуль-символа.

Строки также могут вписываться в память и считываться при помощи символьных указателей. Символьный указатель на строку объявляется следующим образом: char *pstr = ЗДРАВСТВУЙ,

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

Символ

Символ – это один знак. Любой – буква, цифра, арифметический знак или пробел , знак препинания или подчеркивания... А также специальные символы – переход на новую строку, BackSpace, знак доллара или процент . Тип "символ" в Delphi обозначается Char:

ShowMessage("Вы ввели " + c);

ShowMessage("Переход на новую" + c + "строку");

Мы уже говорили, что символы берутся из таблицы символов ANSI или UNICODE. Большинство символов используются, некоторые символы являются служебными. Обратите внимание, что большая буква "А" и маленькая "а" - это разные символы! Также разными символами являются латинская "с" и русская "с", хотя они похожи, как две капли воды.

Нулевой символ не используется, он зарезервирован как полный нуль. Программисты нашли достойное применение этому символу, используя его в событиях ввода текста, когда требуется запретить пользователю ввод каких-либо символов. Служебные символы мы не можем увидеть в текстовом поле . Служебные символы, это , <Enter >, <Tab > и другие. Каждый символ обрабатывается компьютером как число от 0 до 255, таким образом, слово "ПРИВЕТ" в памяти машины будет выглядеть как набор цифр: "207 208 200 194 197 210".

Функции работы с символами

В практике часто приходится обрабатывать отдельные символы. Переменным символьного типа Char можно присваивать значения таким образом:

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

if b > c then ShowMessage("Истина!")

else ShowMessage("Ложь!");

При работе с символьными переменными часто используют функции Chr() и Ord(). Функция Chr() принимает в качестве параметра число, и возвращает символ, который соответствует этому числу в таблице ANSI :

function Chr (X: Byte): Char;

Функция Ord() совершает прямо противоположное действие, она принимает в качестве параметра символ, и возвращает число, под которым этот символ хранится в таблице ANSI :

function Ord (C: Char): Byte;

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

В первой строке в переменную a мы записали символ "И", которому в таблице символов соответствует номер 200. Во вторую, целую переменную, мы записали число 200, так как символ с этим номером был записан в переменную a, которую мы передали в качестве параметра. Наконец, в третьей строке мы в целую переменную записали число 102, этот номер соответствует символу "f".


Строка

Строка – это набор символов. Строку можно представить в виде статичного или динамичного массива символьных данных. Типы строк мы уже разбирали в "Управляющая конструкция if, цикл for" : AnsiString – строка из ANSI – символов, и WideString – строка из UNICODE – символов.

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

s:= "Это многострочная" + #13 + "строка";

Как видно из примера, строку можно составлять из нескольких подстрок, и даже добавлять в нее отдельные символы. В примере мы добавили символ под номером 13, это символ перехода на новую строку. В результате выполнения этого кода процедураShowMessage() выведет на экран сообщение, разбитое на две строки:

Это многострочная

ShortString – короткая строка из ANSI – символов. Может содержать от 0 до 255 символов. Используется нечасто. Собственно, вы можете объявить тип String с заранее указанным размером:

Как видите, строка объявляется с числовым индексом, почти как массив . Собственно, строка символов и есть массив символьных данных, и обращаться с ней можно также. Индексация символов в строке начинается с единицы, то есть, индексу 1 соответствует 1-й символ строки.

stroka:= "Привет";

stroka := "а"; //изменили 5-й символ строки

ShowMessage(stroka); //результат: строка "Приват"

Это тоже строка, и в будущем нам придется с ней сталкиваться. Эта строка работает совершенно иначе, чем String. СтрокаString представляет собой массив символов, в нулевом элементе которого содержится количество байт , отводимых под эту строку. А переменная типа PChar – это не сама строка, а указатель на начало строки, то есть переменная указывает на первый символ строки в памяти компьютера. А где же тогда PChar хранит количество байт в строке?! А нигде! Мы уже говорили о таблице символов ANSI , и выяснили, что нулевой символ – пустой. Вот последний символ PChar как раз и хранит этот символ, икомпьютер , найдя его, считает, что строка окончена.

Со строками PChar работать очень неудобно, однако нам придется это делать, когда мы будем работать с функциями WinAPIнапрямую. Функции WinAPI – это функции самой Windows , а не Delphi. Однако Delphi позволяет использовать их. Иногда это бывает необходимо, например, когда средств Delphi недостаточно для выполнения намеченной задачи. Использование таких функций не всегда удобно, однако они выполняются процессором намного быстрее, так как содержатся в самой операционной системе. Пример – функция MessageBox().

Вы уже привыкли выводить сообщения с помощью функции Delphi ShowMessage()? Привыкайте к новой функции!

Application.MessageBox("строка 1", "строка 2",[ кнопки + тип_окна]);

· строка 1 - выводит текст внутри окна.

· строка 2 – текст в заголовке окна.

Если не указывать [кнопки + тип_окна] то выйдет простое окно с кнопкой ОК, как в функции ShowMessage().

Слово «символ» многозначно; в частности, под символом в программе Adobe Illustrator понимается векторный объект, который хранится в палитре Symbols (Символы) (рис. 1), открываемой командой Window=>Symbols (Окно=>Символы), и предназначен для многократного использования. Работа с символами несколько напоминает клонирование объектов, но только на первый взгляд, поскольку это принципиально разные технологии с различными возможностями и назначением. Общее состоит лишь в том, что любой символ из палитры Symbols может быть многократно размножен.

Среди возможностей работы с символьными объектами Adobe Illustrator — не только многократная вставка того или иного символа из палитры Symbols , но и разнообразные манипуляции с ним. Символы можно распылять, как краску из баллончика, увеличивать, уменьшать и поворачивать, можно менять расположение символов в группе, плотность символьных объектов, степень прозрачности и тонирования и т.д. Для этих целей в программе имеется группа специальных символьных инструментов — Symbol Tool , в которую входят инструменты Symbol Sprayer (Распылитель символов), Symbol Shifter (Сдвиг символов), Symbol Scruncher ((Плотность объектов), Symbol Sizer (Размер символов), Symbol Spinner (Вращение символов), Symbol Stainer (Тонирование символов), Symbol Screener (Прозрачность символов) и Symbol Styler (Стилизация символов) (рис. 2). И что самое главное — изменение символа при необходимости можно мгновенно обновить все его копии на создаваемом изображении; причем совершенно неважно, насколько значительными были сделанные вами изменения.

Стоит отметить, что использование в изображениях символьных объектов имеет немало преимуществ: благодаря тому что символы представляют собой подобные друг другу объекты (это означает, что каждый элемент в рисунке ссылается на свой оригинальный образец-символ), происходит уменьшение общего объема изображения, что актуально как при создании web-графики, так и при разработке анимации, картографических изображений и пр. Кроме того, существенно упрощается работа с изображением, поскольку любое изменение символа в палитре Symbols автоматически приводит к соответствующему редактированию всех построенных на его основе графических объектов в изображении, что существенно ускоряет разработку. Последнее особенно важно для дизайнеров, занимающихся разработкой картографических объектов — карт, схем и диаграмм, содержащих большое количество однотипных элементов, играющих роль условных обозначений. Это избавляет дизайнеров от многократных операций копирования и вставки, а также от редактирования каждого однотипного символа вручную. Технически весь процесс разработки, например, карты значительно упрощается, а число необходимых шагов уменьшается. В итоге для создания картографического изображения достаточно разместить объекты-символы в нужных местах, а все прочие их характеристики можно настроить позже, причем одновременно для всех задействованных в изображении однотипных элементов.

Входящие в поставку символы находятся в нескольких библиотеках (правда, общее их число не велико (рис. 3)), а доступ к нужной библиотеке можно получить при помощи команды Window=>Symbols Library (Окно=>Библиотека символов). Количество символов может быть многократно увеличено как за счет скачивания необходимых в работе символов из Интернета, так и путем собственноручного создания новых символов. Собственно говоря, любой объект, группа объектов или изображение в целом может быть сохранено в качестве символа независимо от того, включает ли оно нарисованные элементы, текст, внедренные изображения или комбинацию перечисленных элементов. Это очень удобно, так как позволяет пополнить библиотеку Symbols теми графическими элементами, которые многократно используются в конкретной разработке.

Работа с отдельными символами палитры Symbols

Размещение отдельных символов в документе

Для примера рассмотрим простейшую ситуацию, когда некий алгоритм необходимо представить в виде схемы. Создайте новый документ и откройте библиотеку символов Charts , воспользовавшись командой Window=>Symbols Library=>Charts (Окно=>Библиотека символов=>Карта). Затем последовательно перетаскивайте нужные символы из палитры символов в создаваемую схему и размещайте их нужным образом. Есть и другой способ перемещения символа в изображение — можно выбрать символ и щелкнуть на кнопке Place Symbol Instance (Поместить экземпляр символа) палитры Symbols , что приведет к появлению одного экземпляра символа в центре изображения. Затем точно так же вставленный символ можно будет переместить, предварительно выделив инструментом Selection (Выделение) или Direct Selection (Частичное выделение).

По окончании работы, чтобы добиться определенной симметричности элементов схемы, потребуется последовательно выделять инструментом Direct Selection при нажатой клавише Shift те символы, которые нужно разместить по центру документа либо на одной горизонтали или по одной вертикали, и щелкать на соответствующих кнопках палитры Align (Выравнивание). Результат может напоминать рис. 4.

Если размеры каких-то объектов вас не устраивают, то их легко изменить, выделив конкретный символьный объект инструментом Selection , что автоматически приведет к заключению объекта в габаритный контейнер, и откорректировав размер обычным образом — перетаскиванием одного из маркеров контейнера (рис. 5).

Если необходимо изменить вариант оформления всех или только некоторых символов, то проще всего воспользоваться одним из встроенных стилей. Для этого выделите редактируемые объекты инструментом Selection (рис. 6) и щелкните на подходящем стиле в палитре Styles (Стили) — в данном примере был выбран стиль Blue Goo (рис. 7).

Если ни один из стилей оформления в данной ситуации вам не подходит, тогда потребуется разорвать связь с символьными элементами палитры Symbols , выделив объекты изображения инструментом Selection и щелкнув на кнопке Break Link to Symbol Symbols . Внешний вид выделенной области тут же изменится — символы окажутся заключенными в габаритные контейнеры и превратятся в обычные векторные объекты (рис. 8). Это будет означать, что у любого элемента можно будет изменить особенности заливки и границы, например установив градиентную заливку, и выполнить с ними любые иные преобразования (рис. 9).

Рис. 8. Изменение характера выделения элементов схемы после разрыва связей

Копирование символов в документе

Символьные объекты так же легко копировать, как и обычные векторные, при нажатой клавише Alt . Для примера перетащите любой из символов из палитры Symbols на рабочий лист. В случае необходимости скорректируйте его размер и нажав клавишу Alt многократно, начинайте дублировать, перемещая мышь при нажатой левой кнопке (рис. 10).

Редактирование отдельных символов в документе

Внедренные в изображение символьные элементы можно трансформировать (изменять размеры, поворачивать, отображать и пр.), как и обычные векторные объекты, выравнивать, пользуясь кнопками палитры Align (Выравнивание), менять прозрачность и режим смешивания в палитре Transparency (Прозрачность) (рис. 11 и 12) и оформлять различными стилями из палитры Styles (Стили).

Рис. 12. Результат внедрения в растровое изображение серии символов с последующей их трансформацией, изменением степени прозрачности и режима смешивания

Благодаря наличию специальных символьных инструментов из группы Symbol Tool редактировать отдельные символы можно и совершенно иным способом — в некоторых случаях это оказывается удобнее, чем, например, классические варианты трансформации. Чтобы оценить возможности инструментов из группы Symbol Tool , немного поэкспериментируем с ними на примере создания нового изображения. Для начала переместим из палитры Symbols символ огня (рис. 13). В палитре инструментов активизируем инструмент Symbol Sizer (Размер символов) и несколько раз щелкнем на внедренном символе, пока размер изображения не станет достаточно большим (рис. 14). Некоторое преимущество применения Symbol Sizer по сравнению с обычным выделением объекта инструментом Selecton и последующим изменением размера путем перемещения граничных точек габаритного контейнера заключается в том, что для пропорционального изменения размеров нет необходимости удерживать клавишу Shift , поскольку по умолчанию инструмент настроен именно на пропорциональное изменение размеров.

После этого возьмем инструмент Symbol Shifter (Сдвиг символов) и перетащим символ в правый нижний угол (рис. 15). С помощью инструмента Symbol Spinner (Вращение символов) слегка повернем символьный объект (рис. 16), добавим на передний план еще один символ из библиотеки символов Nature , для открытия которой воспользуйтесь командой Window=>Symbols Library=>Nature (Окно=>Библиотека символов=>Природа) (рис. 17). Затем изменим тональность цветов символа-огня инструментом Symbol Stainer (Тонирование символов) — для этого выделим символ инструментом Selecton , установим подходящий цвет в окне Fill (Заливка) и щелкнем на символе. В итоге внешний вид изображения мгновенно изменится: цветовые переходы сохранятся, но тональность их станет другой, приблизившись к цвету, заданному в окне Fill (рис. 18). Обратите внимание, что при помощи символьных инструментов можно изменить тональность, но не цвета заливки и не границы символьных объектов — последнее возможно лишь после осуществления разрыва связи между символом в палитре Symbols и его копией в изображении (команда Break Link to Symbol — Разорвать связь с символом).

В заключение слегка уменьшим прозрачность символа-огня. Для этого выделим символ, выберем инструмент Symbol Screener (Прозрачность символов) и изменим вначале его параметры, так как по умолчанию он очень сильно уменьшает прозрачность. Дважды щелкнем на инструменте Symbol Screener и снизим интенсивность воздействия инструмента, уменьшив значение в поле Intensity (Интенсивность) с 8, например, до 2 (рис. 19). Щелкнем на символе огня, и полученный результат может напоминать рис. 20.

А теперь превратим изображение в карандашный рисунок, изменив стилизацию объектов при помощи инструмента Symbol Styler (Стилизация символов). Выделите оба символа инструментом Selection , включите инструмент Symbol Styler , а затем активизируйте нужный стиль — в данном примере был выбран стиль 1-pt Outside Stroke (рис. 21).

Рис. 21. Карандашный рисунок, сформированный на основе символьных объектов

Создание новых символов

Как уже было отмечено, символы могут быть созданы из любых объектов, которые используются в программе Adobe Illustrator, включая простые и составные контуры, текстовые объекты, импортированные пиксельные изображения, градиентные сетки и группы объектов, а также сами символы.

Формирование нового символа из сложного объекта с градиентной заливкой

Допустим, у вас уже имеется векторный объект в виде кнопки с градиентной сеткой (рис. 22). Чтобы создать на его основе символ и разместить оный в палитре Symbols , необходимо выделить объект инструментом Selection и перетащить его в палитру или щелкнуть на кнопке New Symbol (Новый символ) в палитре Symbols (рис. 23). Точно так же создадим еще одно идентичное изображение — аналогичную кнопку, но зеленого цвета (оба символа нам потребуются в дальнейшей работе) (рис. 24). Если необходимо, чтобы одновременно этот символ стал символом и на изображении, то есть чтобы возникла связь между символом и соответствующим ему символьным объектом на рисунке, то при перетаскивании необходимо удерживать нажатой клавишу Shift .

Рис. 22. Исходное изображение (кнопка и соответствующая ей палитра Layers)

Ничего страшного, если символ, помещенный в палитру, оказался неудачным — его несложно удалить, выделив в палитре Symbols и щелкнув на кнопке Delete Symbol (Удалить символ) данной палитры.

Следует иметь в виду, что при открытии или создании нового изображения открывшаяся палитра Symbols будет иметь первоначальный вид, то есть созданные новые символы там будут отсутствовать. Поэтому необходимо сохранить изображение с новыми символами в палитре обычным образом при помощи команды File=>Save (Файл=>Сохранить) с расширением *ai. После этого сохраненную палитру можно будет открывать как соответствующую библиотеку и использовать в работе.

Теперь попробуем воспользоваться созданным символом на примере формирования картографического изображения. Откройте исходную карту (рис. 25), на которую необходимо добавить в виде специальных значков места расположения городов и курортов. Откроем палитру Symbols с только что созданными символами командой Window=>Symbols Library=>Other Library (Окно=>Библиотека символов=>Другие библиотеки), а затем последовательно разместим голубые кнопки в местах нахождения городов (рис. 26), зеленые — курортов (рис. 27).

Рис. 27. Окончательный внешний вид созданного картографического изображения с отмеченными городами и курортами

Если в созданном изображении, содержащем многочисленные копии символов, нужно изменить какие-то из них, например уменьшить прозрачность некоторых из символов (они будут соответствовать менее дорогим курортам), то это действие выполняется в два этапа. Вначале нужно выделить на изображении инструментом Direct Selection редактируемые символьные объекты, а затем уменьшить их непрозрачность в палитре Transparency (рис. 28). Точно так же можно изменить у символьных элементов размер, вызвав команду Transform=>Scale (Трансформация=>Размер) из всплывающего меню (рис. 29), и ряд других параметров. В случае необходимости более серьезных изменений, например для смены заливки, придется сначала превращать символ в векторный объект и только затем производить его редактирование.

Рис. 28. Результат одновременного изменения прозрачности у нескольких символьных объектов (изображение и палитра Transparency)

Рис. 29. Результат одновременного изменения размера у нескольких символьных объектов (изображение и окно Scale)

Формирование нового символа с применением Blend-перехода

А теперь рассмотрим более сложный вариант. Предположим, наша задача состоит в том, чтобы создать карту — схему проезда, например, к офису компании (сегодня подобные схемы имеются в Интернете на многих сайтах). Если при подготовке такой карты не учитывать разнообразие архитектуры, а все здания отображать в виде неких стилизованных типовых строений, то с помощью символьных объектов в программе Adobe Illustrator это можно реализовать достаточно быстро.

Для создания типового здания сформируем два прямоугольных векторных контура и свяжем их с помощью Blend-перехода, установив для него вариант Smooth Color (Сглаженный цветовой переход) (рис. 30), — в результате получится параллепипед, который и будет отображать здание. Затем добавим к нему окна, а учитывая, что окон придется рисовать довольно много, проще будет предварительно создать соответствующий символ и разместить его в палитре Symbols (рис. 31). После этого добавим к стилизованному зданию окна путем обычного перетаскивания символа окна на здание (рис. 32).

Как уже было сказано, предполагаемая карта-схема будет состоять из совершенно одинаковых зданий, вследствие чего созданное здание стоит сохранить в виде символа в палитре Symbols , предварительно выделив его инструментом Selection (рис. 33). После этого приступить к созданию карты уже не составит труда — достаточно будет вставлять символы-дома в нужные части карты, выравнивать их относительно центра (кнопка Vertical Align Center палитры Align ) и относительно друг друга (кнопки Vertical Distribute Center и Horizontal Distribute Center палитры Align ), добавлять к домам номера, а между ними создавать улицы и зеленые массивы. Возможно, в начале работы карта-схема будет иметь примерно такой вид, как на рис. 34.

Формирование нового символа из кисти

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

Можно, конечно, на основе подходящей кисти создать новую, но есть и другой способ, причем более быстрый и удобный — создать на основе кисти в виде стрелки специальный символ и подредактировать его в по своему вкусу. Рассмотрим этот вариант подробно: из библиотеки кистей откройте палитру Arrow Sample , применив команду Window=>Brush Library=>Arrow Sample (Окно=>Библиотека символов=>Образцы стрелок), выберите подходящую кисть (в данном случае задействована кисть Arrow 144) и сформируйте фрагмент стрелки (рис. 35). Перетащите ее в палитру Symbols при нажатой клавише Shift , чтобы образец на рисунке автоматически превратился в символ — это будет временный символ «Стрелка ». Затем обычным образом уменьшите ее размер, разорвите связь с палитрой Symbols , щелкнув на кнопке Break Link to Symbol (Разорвать связь с символом), находящейся внизу палитры Symbols , и добавьте к стрелке, например, границу (можно применить и что-нибудь более интересное — наложить подходящий фильтр, создать Blend-переход и т.п.). После этого вновь перетащите ее в палитру Symbols , а временный символ «Стрелка» удалите, выделив его и щелкнув на кнопке Delete Symbol (Удалить символ) данной палитры (рис. 36). В завершение нарисуйте путь до офиса с применением только что созданного символа «Стрелка ». Не забывайте, что размножать символы быстрее будет не путем многократного перестаскивания из палитры Symbols , а путем перемещения на рисунке символа при нажатой клавише Alt . Возможно, что в итоге изображение примет такой вид, как представлен на рис. 37.

Автоматическая замена символов на рисунке

Если в созданном изображении уже использованы какие-то символы (из числа входящих в поставку или созданных вручную) и в ходе работы оказалось, что некоторые из них необходимо заменить на другие, имеющиеся в палитре Symbols , то это действие займет считаные секунды. Для этого на созданном ранее рис. 27 выделите инструментом Direct Selection заменяемые символы, в палитре Symbol s выделите символ, на который необходимо произвести замену, и выберите из меню палитры команду Replace Symbol (Заменить символ) (рис. 38) — все выделенные символы будут заменены.

Рис. 38. Результат замены нескольких символьных объектов (изображение и палитра Symbols)

Редактирование символов в палитре Symbols

Предположим, что какой-то из символов палитры Symbols (независимо от того, входит он в одну из библиотек или был создан вами) необходимо кардинально изменить. Это возможно только после осуществления разрыва связи, поэтому выберите один из уже созданных нами символов в виде кнопки и щелкните на кнопке Break Link to Symbol (Разорвать связь с символом), находящейся внизу палитры Symbols . Символ вновь станет обычным векторным объектом, и его будет несложно изменить. Поменяем, например, цвет кнопки с зеленого на красный (рис. 39).

Рис. 39. Видоизмененная палитра Symbols с внедренными символами-кнопками и отредактированным символом в виде векторного объекта (это видно по маркерам выделения)

Чтобы заменить символ в палитре Symbols его отредактированной версией, выделите измененный символ, активизируйте исходный символ в палитре Symbols и затем из меню палитры выберите команду Redefine Symbol (Переопределить символ) (рис. 40) — это приведет к изменению символа в палитре (рис. 41). Обратите внимание, что если редактирование символа вы производили в изображении, где он был задействован, — в нашем случае, например, в измененной палитре Symbols (см. рис. 27), то переопределение символа автоматически приведет не только к его замене в палитре Symbols , но и к обновлению всех его копий на изображении (рис. 42).

Рис. 42. Картографическое изображение после переопределения символа, использованного ранее для обозначения курортов, в соответствии с палитрой Symbols

Работа с группами символов

Если речь идет об одновременном размещении и последующей обработке не одного, а сразу нескольких экземпляров одного и того же символа (то есть группы символов), то потребуются специальные символьные инструменты Symbol Tool: Symbol Sprayer (Распылитель символов), Symbol Shifter (Сдвиг символов), Symbol Scruncher ((Плотность объектов), Symbol Sizer (Размер символов), Symbol Spinner (Вращение символов), Symbol Stainer (Тонирование символов), Symbol Screener (Прозрачность символов) и Symbol Styler (Стилизация символов). У каждого инструмента этой группы имеются собственные настройки, которые определяются в диалоговом окне Symbolism Tool Options (Параметры инструмента «Символьные объекты»), вызываемом двойным щелчком мыши.

Такие группы символов представляют собой единый объект (рис. 43), и все последующие возможные в их отношении преобразования: трансформация, изменение насыщенности, цвета, расположения, размера, поворота, прозрачности и наложения стилей — применяются сразу ко всем элементам группы.

Распыление группы символов

Для примера откроем изображение (рис. 44) и попытаемся распылить на нем снежинки — подходящий образец снежинки имеется в библиотеке символов Nature . По сравнению с размером исходного изображения образец снежинки слишком велик, поэтому вначале вставьте его единственный экземпляр обычным образом, перетащив из палитры на рисунок (рис. 45). Затем активизируйте инструмент Selection и, не снимая выделения со снежинки, уменьшите ее размер до приемлемого (рис. 46) при нажатой клавише Shift , чтобы сохранить пропорции. Перетащите новый образец символа-снежинки в палитру Symbols и оставьте его там в качестве активного символа.

После этого выберите инструмент Symbol Sprayer и украсьте изображение, распылив по рисунку снежинки, — это несложно, тем более что технология работы с Symbol Sprayer очень напоминает работу с распылителем в любом графическом пакете. Вполне возможно, что часть снежинок окажется за пределами рисунка (рис. 47), — в этом случае выделите инструментом Selection всю группу снежинок и измените ее размеры обычным образом (рис. 48).

Рис. 47. В результате распыления символов инструментом Symbol Sprayer часть снежинок оказалась вне рисунка

Если параметры настройки инструмента Symbol Sprayer вас не устраивают (по умолчанию для всех его настроек берутся средние значения), то их несложно скорректировать, дважды щелкнув на инструменте и внеся соответствующие корректировки в окне Symbolism Tool Options . Будем считать, например, что нас не устраивает цвет снежинок и плотность их расположения. Для изменения цвета, а точнее для того, чтобы символы создавались с учетом цвета, выбранного в окне Fill (Заливка), в списке Stain (Окрашивание) потребуется установить вариант User Defined (Определенный пользователем). А для увеличения плотности следует увеличить значение параметра Symbol Set Density (Плотность набора символов), например, как на рис. 49. Результат может напоминать рис. 50.

Рис. 50. После создания дополнительных символьных объектов снежинки распыляются более плотно и имеют более темный оттенок в соответствии с цветом, установленным в окне Fill (Заливка)

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

  • Scrunch (Плотность объектов) — относительная плотность объектов с учетом исходного размера символа;
  • Size (Размер) — размер распыляемых символов с учетом исходного размера символа;
  • Spin (Вращение) — определение поворотов генерируемых символов с учетом перемещения курсора мыши;
  • Screen (Прозрачность) — учет степени прозрачности символов;
  • Style (Стиль) — определение характера оформления символов с учетом параметров активного стиля.

Для каждого из этих параметров возможны два варианта установок: Average (Средний) добавляет новый экземпляр символа со средним значением параметров, а User Defined (Определенный пользователем) обеспечивает генерацию символов с учетом конкретных настроек пользователя.

В поле Diameter (Диаметр) устанавливается диаметр окружности воздействия инструмента, в поле Intensity (Интенсивность) определяется степень изменения генерируемых символов — чем больше значение, тем больше степень изменения.

Кроме того, лучше работать с включенным флажком Show Brush Size and Intensity (Отображать размер кисти и интенсивность) — в этом случае на экране в виде окружности отображается размер распылителя символов, определяющий площадь воздействия инструмента.

Редактирование группы символов

В качестве исходного изображения возьмем рис. 51, распылим в его нижней части символы травы из библиотеки символов Nature и отредактируем размер полученной группы символов в соответствии с размером исходного изображения (рис. 52). Затем, чтобы увеличить плотность объектов в данной группе символов, вызовем меню инструмента Symbol Scruncher (Плотность объектов), дважды щелкнув на инструменте, и увеличим значение параметра Symbol Set Density (Плотность набора символов), например как на рис. 53. Далее щелкнем на выделенной группе символов, что приведет к их уплотнению (рис. 54).

Дополним изображение, распылив еще несколько групп символов травы, и добавим два символьных объекта в виде камней. Переместим последние под траву — для этого потребуется выделить каждый из объектов, щелкнуть на нем правой кнопкой мыши и выбрать команду Arrange=>Send Backward (Переместить=>Переместить назад) (рис. 55).

Рис. 55. Изображение после добавления нескольких групп символов и двух единичных символов

Сделаем траву в правом нижнем углу изображения потемнее с помощью инструмента Symbol Stainer (Тонирование символов). Выделим соответствующую группу символов инструментом Selecton , установим темно-зеленый цвет в окне Fill (Заливка) и щелкнем на группе символов (рис. 56) — для большего эффекта можно поперемещать мышь по символьной группе, что приведет к дальнейшему постепенному перекрашиванию символов. В результате символы травы сохранятся, но их цветовой тон изменится в соответствии с цветом, определенным в окне Fill (рис. 57).

Рис. 56. Воздействие инструментом Symbol Stainer (Тонирование символов) на группу символов

После этого осветлим траву в левом верхнем углу. Это можно сделать как вышеописанным способом, предварительно установив в палитре светло-зеленый цвет, так и изменяя степень прозрачности соответствующей группы символов инструментом Symbol Screener (Прозрачность символов). Воспользуемся вторым способом, то есть выделим группу символов и щелкнем на группе (или проведем по ней — от этого зависит, сколько символов и в какой степени будут подвержены воздействию) инструментом Symbol Screener (рис. 58). Возможно, что после преобразований изображение станет походить на рис. 59.

Рис. 58. Воздействие инструментом Symbol Screener (Прозрачность символов) на группу символов

Введение

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

Символы

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

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