Andrew Fionik дата публикации 01-10-2004 17:30 урок из цикла:
Символьные и строковые типы данныхИтак, с числами мы разобрались. Настал черед текста. Delphi позволяет манипулировать текстовыми данными в виде отдельных символов, а также в виде последовательностей символов - строк.
Тут следует сделать небольшое лирическое отступление по поводу изложения материала. Дело в том, что тема хранения текстовых данных чрезвычайно обширна как по количеству, так и по сложности. Если сразу же вывалить ее на голову простого чайника во всей полноте, то он мало чего поймет и, скорее всего, запутается. Поэтому мы поступим, как делают в школе на уроках физики. Вначале законы физики объясняются по-простому, в виде Ньютоновской механики, а уж потом, много позже, начинаем рассказывать релятивистские сказки от сказочника Эйнштейна, и видим, что первоначальное мировоззрение оказывается всего лишь упрощенным представлением настоящей картины мира. Так же поступим и здесь.
Базовый тип данных (т.е. то на чем основываются все остальные текстовые типы данных) - Char. Переменная типа Char может хранить всего один символ, один из набора 256 символов. Каждый символ имеет свой код. На самом-то деле компьютер оперирует не символами, (он не знает что это такое) а кодами символов. Например, во время печати символа с определенным кодом он ищет графическое изображение символа в таблице изображений символов за определенным номером, а потом выводит именно это графическое изображение на дисплей. Символы можно сравнивать между собой на равенство и на определение, какой больше или меньше, тогда компьютер опять же сравнивает не сами символы, а их коды.
Приблизительно таблицу символов можно описать примерно так. В начале идут различные служебные управляющие символы, которые не имеют графического представления. Например, это символы табуляции, возврата каретки, перевода строки и т.п. Потом идут знаки препинания '!', '?', '.' и т.п. Далее идут цифры '1', '2', '3' и т.д. Следующими идут литеры английского алфавита 'A', 'B', 'C',...,'Z', 'a', 'b', 'c',..., 'z'. Завершают таблицу литеры национального алфавита: 'А', 'Б', 'В',...,'Я','а', 'б', 'в',...,'я'.
Следует заметить, что существует масса таких таблиц символов. Разные системы могут по-разному интерпретировать коды символов по той простой причине, что они руководствуются разными таблицами символов. В этом опусе мы будем использовать таблицу символов называемую Windows Code Page 1251 (Cyrillic). Это таблица символов для кириллицы в системах Microsoft Windows. Это означает что в системе Windows каждый символ с определенным кодом будет интерпретироваться одинаково для всех программ, если они конечно не реализуют какую-то свою, специфическую обработку символов.
Как мы уже говорили раньше, переменные символьных типов могут содержать только один символ, а не два и не три и т.д. Пример использования типа Char:
program CharDemo1;
var
A:Char;
begin
A:='Z';
WriteLn(A);
end.
| |
Эта программа присваивает переменной типа Char значение символа 'Z' а потом выводит его на консоль.
А вот эта программа не будет скомпилирована компилятором по причине ошибки компиляции. Переменной A может быть присвоено значение только одного символа.
program CharDemo2;
var
A:Char;
begin
A:='ZZZ';
WriteLn(A);
end.
| |
Для типа данных Char определены также две операции - получение кода символа из переменной типа Char и преобразование кода символа в значение типа Char. Эти операции реализованы двумя функциями стандартной библиотеки - Ord и Chr.
Функция Ord принимает один параметр типа Char а возвращает значение типа Byte которое и представляет собой код символа. Функция Chr делает все с точностью наоборот - принимает значение типа Byte а возвращает значение типа Char.
Примеры использования функций Ord и Chr:
program CharDemo3;
const
A='M';
var
B:Char;
CodeA,CodeB:Byte;
begin
WriteLn('Value of A is ',A);
CodeA:=Ord(A);
WriteLn('Code of A is ',CodeA);
CodeB:=CodeA+1;
B:=Chr(CodeB);
WriteLn('Value of B is ',B);
WriteLn('Code of B is ', CodeB);
CodeB:=CodeA-1;
B:=Chr(CodeB);
WriteLn('Value of B is ',B);
WriteLn('Code of B is ', CodeB);
ReadLn;
end.
| |
При выполнении этой программы должен быть выдан вот такой текст:
Value of A is M
Code of A is 77
Value of B is N
Code of B is 78
Value of B is L
Code of B is 76
Переменная типа String представляет собой последовательность символов - строку. Мы можем определять длину строки, можем добавлять к строке другие строки и символы, можем заменять произвольные части строки на другие строки и символы, можем удалять части строки.
Пример объявления переменной типа String:
program StringDemo1;
var
A:String;
begin
A:='Hello world!';
WriteLn(A);
ReadLn;
end.
| |
Операции над строками
Ниже перечислены основные, наиболее общие операции которые могут производиться со строками. В основном все операции реализуются через функции стандартной библиотеки.
- присваивание строке значения другой строки или константы
- получение значения строки
- получение длины строки (количество символов в строке)
- получение значения конкретного символа (символа находящегося в определенной позиции строки)
- изменение значения конкретного символа в строке
- слияние (конкатенация) двух и более строк
- выделение подстроки из строки
- вставка одной строки внутрь другой
- удаление части строки
- определение позиции вхождения одной строки в другую
- изменение регистра символов
- сравнение строк на равенство или больше/меньше
Кроме этих операций, существует еще масса других, более специализированных, но о них позже.
Подпрограммы
Забегая немного вперед, следует указать, что многие операции над строками выполняются с помощью различных подпрограмм. Подпрограмма - кусочек программного кода, который имеет идентификатор и может быть вызван по нему для выполнения какой-либо задачи. Зачастую подпрограмма требует передать ей какие-нибудь параметры. В качестве параметров используется либо выражение, либо идентификатор чего-либо. Например, идентификатор переменной или константы. Подпрограммы подразделяются на процедуры и функции. Разница между ними лишь в наличии возвращаемого результата. Функции возвращают результат своего выполнения, а процедуры не возвращают никакого результата, только выполняют какое-то действие. Например, Sin - функция, которая вычисляет значение синуса переданного ей параметра и возвращает результат вычисления в виде вещественного значения. В противоположность ей WriteLn является процедурой, которая никаких значений не возвращает, но выполняет действие - вывод значений переданных ей параметров на консоль. Процедуры вызываются следующим образом:
Имя_процедуры(Параметр1, Параметр2, ..., ПараметрN);
Вызов функции может быть использован внутри какого-либо выражения (для его вычисления). Также вызов функции может быть использован в операторе присваивания, чтобы присвоить какой-нибудь переменной результат выполнения функции.
Имя_переменной:=Имя_функции(Параметр1, Параметр2, ..., ПараметрN);
Присваивание значения строке, получение содержимого строки
Строковой переменной может быть присвоено значение, как и любой другой переменной. Единственное ограничение состоит в том, что тип значения должен быть String или Char (что такое один символ как не строка длиной 1).
program StringDemo01;
const
A='Hello, world';
var
B,C:String;
begin
B:=A;
WriteLn(B);
C:=B;
WriteLn(C);
ReadLn;
end;
| |
Получение длины строки
Для определения длины строки в символах используется функция стандартной библиотеки Length. Функция Length получает на вход один единственный параметр, идентификатор строковой переменной или выражение строкового типа. Результат функции, количество символов в строке, имеет тип Integer.
Формат вызова:
Length(идентификатор переменной или выражение типа String)
Пример:
program StringDemo02;
const
A='Hello, world';
var
B:String;
L:Integer;
begin
B:=A;
L:=Length(B);
WriteLn('Length of "',B,'" is ', L);
ReadLn;
end;
| |
Получение и установка отдельного символа строки
К символам строки можно обращаться по их индексу (позиции в строке). Индекс первого символа строки 1. Индекс последнего символа строки будет равен результату вызова функции Length, которой в качестве параметра будет передана строка. Обратите внимание на то, что индекс первого символа 1, а не 0 как обычно делается в различных структурах данных, которые могут содержать много элементов (вообще-то больше одного). При попытке обращения к символу с индексом меньше 0 или больше Length(идентификатор строки) возникает ошибка времени выполнения.
Формат обращения к символу строки:
S[I]
... где S - идентификатор строковой переменной, а I - индекс символа.
Выражение вида S[I], где S - идентификатор строковой переменной, возвращает результат типа Char.
Пример доступа к символу строки по индексу:
program StringDemo03;
const
A='Hello, world';
var
B:String;
I:Integer;
C:Char;
begin
B:=A;
WriteLn('First character of string "', B, '" is "',B[1],'"');
I:=Length(B);
C:=B[I];
WriteLn(C);
B[Length(B)]:=B[1];
B[1]:=C;
WriteLn(B);
ReadLn;
end;
| |
Должно вывестись следующее:
First character of string "Hello, world" is "H"
d
dello, worlH
Слияние двух строк (конкатенация)
Строки можно складывать как числовые переменные, используя оператор +. Результатом сложения является более длинная строка, включающая в себя содержимое обеих строк в порядке их употребления в операции сложения. Также существует функция Concat которая выполняет в точности то же действие что и +.
Формат операции конкатенации двух строк:
A+B
или
Concat(A,B)
... где A - идентификатор одной строки или строковое выражение, а B - идентификатор другой строки или строковое выражение.
Пример:
program StringDemo04;
var
A,B,C,D:String;
begin
C:='Hello';
D:='world';
A:=C+D;
B:=C+', '+D;
C:=D+C;
D:=Concat(A+B);
WriteLn(A);
WriteLn(B);
WriteLn(C);
WriteLn(D);
ReadLn;
end;
| |
Результат вывода должен быть следующим:
Helloworld
Hello, world
worldHello
HelloworldHello, world
Выделение подстроки из строки
Иногда бывает необходимо получить часть строки, а не всю ее целиком. Для этого существует функция Copy. Функция Copy получает на вход три параметра - строку, позицию с которой надо начинать копирование и количество символов которые надо скопировать. Формат вызова функции Copy:
Copy(Source,Index,Count);
... где Source - идентификатор строковой переменной или строковое выражение часть которого должна быть скопирована, Index - позиция с которой должно быть осуществлено копирование, Count - количество символов которое должно быть скопировано.
- Если Index больше чем длина строки Source, то функция возвращает пустую строку, т.е. строку, не содержащую символов. Длина пустой строки равняется нулю.
- Если Count указывает больше символов, чем имеется в строке Source, начиная с позиции Index, то копируются все символы Source, начиная с позиции Index и до конца.
Пример выделения подстроки:
program StringDemo04;
var
A,B:String;
begin
A:='Hello, world';
B:=Copy(A,2,5);
A:=Copy('Delphi rulez',1,6)+' great';
WriteLn(B);
WriteLn(A);
ReadLn;
end;
| |
На консоль должно быть выведено следующее:
ello,
Delphi great
Вставка одной строки внутрь другой
Вставка строки выполняется процедурой Insert. Процедура получает на вход три параметра: строку, которую нужно вставить, строку в которую должна быть произведена вставка и позицию, в которой должна быть произведена вставка. Формат вызова:
Insert(Source,Target,Position);
- Source - строка которая будет вставлена
- Target - идентификатор строковой переменной в которую вставляют содержимое Source
- Position - позиция, начиная с которой будет вставлено содержимое Source в Target
Обратите внимание, что это уже не функция, а процедура. Она не возвращает никакого результата, а модифицирует содержимое Target. Еще одна особенность использования процедуры, а не функции заключается в том, что в качестве Target можно передавать только идентификатор переменной, но нельзя передавать выражение или идентификатор константы. Процедура Insert присваивает результат своей работы Target, а присвоить что-либо константе или выражению невозможно по определению.
- Если Position меньше 1, то процедура принимает его равным 1.
- Если Position больше чем Length(Target), то содержимое Source добавляется к Target с конца.
- Если Source является пустой строкой, то Insert ничего не делает
Пример использования Insert
program StringDemo05;
var
A:String;
begin
A:='Happy friends';
Insert(' tree',A,6);
WriteLn(A);
ReadLn;
end;
| |
В результате выполнения этой программы должна быть выведена строка:
Happy tree friends
Удаление части строки
Часть строки может быть удалена с помощью процедуры Delete. Формат вызова процедуры Delete:
Delete(Target,Index,Count);
... где Target - идентификатор строковой переменной, из которой удаляются символы, Index - позиция, начиная с которой производится удаление, Count - количество удаляемых символов.
- Если Index меньше 1 или больше чем Length(Target), то ничего из Target не удаляется.
- Если Count указывает больше символов чем есть начиная с Index, то удаляются символы от Index и до конца строки. Если Count меньше 1, то ничего не удаляется.
Пример использования Delete:
program StringDemo06;
var
A:String;
begin
A:='Happy friends';
Delete(A, 3, 5);
WriteLn(A);
ReadLn;
end;
| |
Результат вывода должен быть:
Hariends
Определение позиции вхождения одной строки в другую
Иногда бывает нужно определить содержится ли одна строка в другой, а также позиция с которой содержимое строк совпадает. Для этого применяется функция Pos. Формат вызова:
Pos(SubStr, Str)
... где Str - строка, в которой производится поиск SubStr. Функция возвращает позицию вхождения в качестве результата. Если строка SubStr не находится в Str, то результат выполнения функции будет равен 0. Функция различает регистр букв - большой и маленький, т.е. подстрока 'dancing' будет найдена в 'We dancing in shadows', но не будет найдена в 'We Dancing In Shadows'.
Пример использования Pos:
program StringDemo07;
var
I:Integer;
begin
I:=Pos('win','Good guys only win in movies');
WriteLn(I);
ReadLn;
end;
| |
Должно быть напечатано число 16.
Изменение регистра символов
Каждый символ, представляющий собой букву, имеет регистр - верхний или нижний. Например, буква "а" может быть заглавной "А" и прописной "а". Заметим что "А" и "а" являются различными символами. Про заглавные буквы говорят, что они имеют верхний регистр. Про прописные буквы говорят, что они имеют нижний регистр. В некоторых случаях нужно преобразовать отдельную строку или символ в верхний или нижний регистр. Это делают функции UpCase, UpperCase, LoCase, LowerCase.
- Формат вызова функции UpCase: UpCase(Source)
-
Source - идентификатор переменной или выражение типа Char. Результат, возвращаемый функцией, также является значением типа Char и представляет собой значение Source преобразованное в верхний регистр.
- Формат вызова функции LoCase: LoCase(Source)
-
Source - идентификатор переменной или выражение типа Char. Результат, возвращаемый функцией, также является значением типа Char и представляет собой значение Source преобразованное в нижний регистр.
- Формат вызова функции UpperCase: UpperCase(Source)
-
Source - идентификатор переменной или выражение типа String. Результат, возвращаемый функцией, также является значением типа String и представляет собой значение Source преобразованное в верхний регистр.
- Формат вызова функции LowerCase: LowerCase(Source)
-
Source - идентификатор переменной или выражение типа String. Результат, возвращаемый функцией, также является значением типа String и представляет собой значение Source преобразованное в нижний регистр.
Пример использования функций изменения регистра:
program StringDemo07;
const
SourceString='Hello world';
var
TargetString:String;
begin
TargetString:=LowerCase(SourceString);
WriteLn(TargetString);
WriteLn(UpperCase(SourceString));
TargetString[1]:=UpCase(TargetString[1]);
TargetString[Length(TargetString)]:=UpCase(TargetString[Length(TargetString)]);
WriteLn(TargetString);
TargetString[1]:=LoCase(TargetString[1]);
WriteLn(TargetString);
ReadLn;
end.
| |
Вывод должен быть следующим:
hello world
HELLO WORLD
Hello worlD
hello worlD
Сравнение строк на равенство или больше/меньше
Строки можно сравнивать между собой как если бы они были числами. Возможны следующие операции сравнения:
- = - сравнение строк на предмет равенства
- <> - сравнение строк на предмет неравенства
- < - сравнение на "меньше"
- > - сравнение на "больше"
- <= - сравнение на "меньше или равно"
- >= - сравнение на "больше или равно"
Результатом сравнения является значение типа Boolean, которое может быть только одним из двух - TRUE (Истина) и FALSE (Ложь).
Правила сравнения:
Сравнение на предмет равенства
- Сравнивается длина строк. Если длина разная, то значит, что строки не равны. Возвращается результат FALSE.
- Если длина одинаковая, производится посимвольное сравнение строк. Как только в какой-либо позиции сравниваемых строк находятся разные символы, возвращается FALSE - строки не равны.
- Если длина строк одинаковая и все символы на соответствующих позициях равны друг-другу, то строки считаются равными. Возвращается результат TRUE.
Сравнение на предмет неравенства
Производится сравнение на предмет равенства, затем результат "переворачивается вверх ногами". Вместо TRUE возвращается FALSE и наоборот.
Сравнение на "меньше"
Поочередно сравниваются коды символов, стоящих на соответствующих позициях. Если одна из строк больше не имеет символов, или символ, стоящий в соответствующей позиции имеет меньший код, то считается что эта строка "меньше".
Пример:
Строка 'Ivan' меньше строки 'Ivar', т.к. первые три символа равны, а четвертый символ в первой строке ('n') меньше чем четвертый символ ('r') во второй строке.
Пример:
Строка 'Doom' меньше чем строка 'Doomsday' потому что четыре первых символа совпадают, но пятого символа в первой строке уже нет, а во второй есть хоть какой-то.
Сравнение на "больше"
Поочередно сравниваются коды символов, стоящих на соответствующих позициях. Если одна из строк еще имеет символы, в то время как другая больше не имеет символов, или символ, стоящий в соответствующей позиции имеет больший код, то считается что первая строка "больше".
Нечеткие сравнения на "меньше или равно" и "больше или равно"
Фактически "меньше или равно" означает "не больше", а "больше или равно" означает "не меньше". Соответственно производится сравнение на предмет "больше" или "меньше" и результат инвертируется.
Пример:
program StringDemo08;
const
C1='Hello World';
C2='Hello day';
C3='Hello baby';
C4='Hello World';
begin
WriteLn(C1=C4);
WriteLn(C1=C2);
WriteLn(C3<>C4);
WriteLn(C1<>C4);
WriteLn(C2<C3);
WriteLn(C1<C4);
WriteLn(C2>C3);
WriteLn(C1>C4);
ReadLn;
end.
| |
Результат должен быть следующий:
TRUE
FALSE
TRUE
FALSE
FALSE
FALSE
TRUE
FALSE
[Функции для работы со строками ] [Строки]
Обсуждение материала [ 30-08-2010 05:16 ] 1 сообщение |