Версия для печати
Символьные и строковые типы данных
http://www.delphikingdom.com/asp/viewitem.asp?catalogID=1061Andrew Fionik
урок из цикла: Азы Delphi.
дата публикации 01-10-2004 17:30Символьные и строковые типы данных Итак, с числами мы разобрались. Настал черед текста. Delphi позволяет манипулировать текстовыми данными в виде отдельных символов, а также в виде последовательностей символов - строк.
Тут следует сделать небольшое лирическое отступление по поводу изложения материала. Дело в том, что тема хранения текстовых данных чрезвычайно обширна как по количеству, так и по сложности. Если сразу же вывалить ее на голову простого чайника во всей полноте, то он мало чего поймет и, скорее всего, запутается. Поэтому мы поступим, как делают в школе на уроках физики. Вначале законы физики объясняются по-простому, в виде Ньютоновской механики, а уж потом, много позже, начинаем рассказывать релятивистские сказки от сказочника Эйнштейна, и видим, что первоначальное мировоззрение оказывается всего лишь упрощенным представлением настоящей картины мира. Так же поступим и здесь.
Тип данных Char
Базовый тип данных (т.е. то на чем основываются все остальные текстовые типы данных) - 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; // Наименование программы - CharDemo3. {$APPTYPE CONSOLE} { Инструкция компилятору Delphi генерировать консольную программу.} const A='M'; // Объявим константу A значение которой 'M' var B:Char; // Объявим переменную B типа Char. CodeA,CodeB:Byte; { Объявим две переменных CodeA и CodeB типа Byte. В них мы будем хранить коды символов.} begin WriteLn('Value of A is ',A); // Напечатаем содержимое константы A CodeA:=Ord(A); // Присвоим переменной CodeA код символа содержащегося в A WriteLn('Code of A is ',CodeA); // Напечатаем код символа содержащегося в A CodeB:=CodeA+1; { Присвоим перменной CodeB код символа следующего за символом в A.} B:=Chr(CodeB); { Преобразуем код символа в значение типа Char и присвоим его B.} WriteLn('Value of B is ',B); // Напечатаем значение B. WriteLn('Code of B is ', CodeB); // Напечатаем код символа лежащего в B. CodeB:=CodeA-1; {Присвоим перменной CodeB код символа предыдущего перед символом в A} B:=Chr(CodeB); // Снова преобразуем код символа в переменную типа Char WriteLn('Value of B is ',B); // Снова печатаем содержимое B... WriteLn('Code of B is ', CodeB); //... и CodeB, они уже немножко другие ReadLn; // ждем нажатия клавиши Enter чтобы завершить программу 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 представляет собой последовательность символов - строку. Мы можем определять длину строки, можем добавлять к строке другие строки и символы, можем заменять произвольные части строки на другие строки и символы, можем удалять части строки.
Пример объявления переменной типа String:
program StringDemo1; // название программы {$APPTYPE CONSOLE} // инструкция компилятору генерировать консольное приложение var // секция объявления переменных A:String; // объявляем переменную A типа String begin // начало тела программы A:='Hello world!'; // присваиваем переменной A строку 'Hello world!' WriteLn(A); // выводим содержимое переменной A на экран ReadLn; // ждем нажатия Enter end. // конец тела программы
Операции над строками
Ниже перечислены основные, наиболее общие операции которые могут производиться со строками. В основном все операции реализуются через функции стандартной библиотеки.Кроме этих операций, существует еще масса других, более специализированных, но о них позже.
- присваивание строке значения другой строки или константы
- получение значения строки
- получение длины строки (количество символов в строке)
- получение значения конкретного символа (символа находящегося в определенной позиции строки)
- изменение значения конкретного символа в строке
- слияние (конкатенация) двух и более строк
- выделение подстроки из строки
- вставка одной строки внутрь другой
- удаление части строки
- определение позиции вхождения одной строки в другую
- изменение регистра символов
- сравнение строк на равенство или больше/меньше
Подпрограммы
Забегая немного вперед, следует указать, что многие операции над строками выполняются с помощью различных подпрограмм. Подпрограмма - кусочек программного кода, который имеет идентификатор и может быть вызван по нему для выполнения какой-либо задачи. Зачастую подпрограмма требует передать ей какие-нибудь параметры. В качестве параметров используется либо выражение, либо идентификатор чего-либо. Например, идентификатор переменной или константы. Подпрограммы подразделяются на процедуры и функции. Разница между ними лишь в наличии возвращаемого результата. Функции возвращают результат своего выполнения, а процедуры не возвращают никакого результата, только выполняют какое-то действие. Например, Sin - функция, которая вычисляет значение синуса переданного ей параметра и возвращает результат вычисления в виде вещественного значения. В противоположность ей WriteLn является процедурой, которая никаких значений не возвращает, но выполняет действие - вывод значений переданных ей параметров на консоль. Процедуры вызываются следующим образом:
Имя_процедуры(Параметр1, Параметр2, ..., ПараметрN);Вызов функции может быть использован внутри какого-либо выражения (для его вычисления). Также вызов функции может быть использован в операторе присваивания, чтобы присвоить какой-нибудь переменной результат выполнения функции.
Имя_переменной:=Имя_функции(Параметр1, Параметр2, ..., ПараметрN);
Присваивание значения строке, получение содержимого строки
Строковой переменной может быть присвоено значение, как и любой другой переменной. Единственное ограничение состоит в том, что тип значения должен быть String или Char (что такое один символ как не строка длиной 1).
program StringDemo01; {$APPTYPE CONSOLE} const A='Hello, world'; // объявляем константу содержащую значение 'Hello world' var B,C:String; // объявляем две переменные типа String - B и C begin B:=A; // присваиваем значение константы A переменной B WriteLn(B); // выводим на консоль содержимое переменной B C:=B; // присваиваем содержимое переменной B в переменную С WriteLn(C); // выводим на консоль содержимое переменной C ReadLn; // ожидаем нажатия Enter end;
Получение длины строки
Для определения длины строки в символах используется функция стандартной библиотеки Length. Функция Length получает на вход один единственный параметр, идентификатор строковой переменной или выражение строкового типа. Результат функции, количество символов в строке, имеет тип Integer.
Формат вызова:
Length(идентификатор переменной или выражение типа String)
Пример:
program StringDemo02; {$APPTYPE CONSOLE} const A='Hello, world'; var B:String; L:Integer; {сюда мы будем заталкивать результат функции Length, количество символов} begin B:=A; // присваиваем значение константы A переменной B L:=Length(B); // присваиваем переменной L количество символов в B // выводим на консоль содержимое переменных B и L WriteLn('Length of "',B,'" is ', L); ReadLn; // ожидаем нажатия Enter end;
Получение и установка отдельного символа строки
К символам строки можно обращаться по их индексу (позиции в строке). Индекс первого символа строки 1. Индекс последнего символа строки будет равен результату вызова функции Length, которой в качестве параметра будет передана строка. Обратите внимание на то, что индекс первого символа 1, а не 0 как обычно делается в различных структурах данных, которые могут содержать много элементов (вообще-то больше одного). При попытке обращения к символу с индексом меньше 0 или больше Length(идентификатор строки) возникает ошибка времени выполнения.
Формат обращения к символу строки:
S[I]
... где S - идентификатор строковой переменной, а I - индекс символа.
Выражение вида S[I], где S - идентификатор строковой переменной, возвращает результат типа Char.
Пример доступа к символу строки по индексу:Должно вывестись следующее:
program StringDemo03; {$APPTYPE CONSOLE} const A='Hello, world'; var B:String; I:Integer; C:Char; begin B:=A; // Выводим значение строки B и первого символа строки B. WriteLn('First character of string "', B, '" is "',B[1],'"'); // вычисляем индекс последнего символа в строке B I:=Length(B); // присваиваем переменной C значение последнего символа строки B C:=B[I]; // Выведем значение последнего символа строки B WriteLn(C); {Теперь поменяем значения последнего и первого символов строки B друг на друга} // присвоим значение первого символа строки B последнему символу B[Length(B)]:=B[1]; {Теперь значение последнего символа строки B потерялось поскольку было переписано значением первого символа. Однако копия этого значения осталась в переменной C, поэтому мы присвоим значение переменной C первому символу строки B} B[1]:=C; // Выведем измененную строку B WriteLn(B); ReadLn; // ожидаем нажатия Enter end;First character of string "Hello, world" is "H" d dello, worlH
Слияние двух строк (конкатенация)
Строки можно складывать как числовые переменные, используя оператор +. Результатом сложения является более длинная строка, включающая в себя содержимое обеих строк в порядке их употребления в операции сложения. Также существует функция Concat которая выполняет в точности то же действие что и +.
Формат операции конкатенации двух строк:A+B или Concat(A,B)... где A - идентификатор одной строки или строковое выражение, а B - идентификатор другой строки или строковое выражение.
Пример:Результат вывода должен быть следующим:
program StringDemo04; {$APPTYPE CONSOLE} 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; {$APPTYPE CONSOLE} 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, а присвоить что-либо константе или выражению невозможно по определению.
Пример использования Insert
- Если Position меньше 1, то процедура принимает его равным 1.
- Если Position больше чем Length(Target), то содержимое Source добавляется к Target с конца.
- Если Source является пустой строкой, то Insert ничего не делает
В результате выполнения этой программы должна быть выведена строка:
program StringDemo05; {$APPTYPE CONSOLE} 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 - количество удаляемых символов.Пример использования Delete:
- Если Index меньше 1 или больше чем Length(Target), то ничего из Target не удаляется.
- Если Count указывает больше символов чем есть начиная с Index, то удаляются символы от Index и до конца строки. Если Count меньше 1, то ничего не удаляется.
Результат вывода должен быть: Hariends
program StringDemo06; {$APPTYPE CONSOLE} var A:String; begin A:='Happy friends'; Delete(A, 3, 5); WriteLn(A); ReadLn; end;
Определение позиции вхождения одной строки в другуюИногда бывает нужно определить содержится ли одна строка в другой, а также позиция с которой содержимое строк совпадает. Для этого применяется функция Pos. Формат вызова:
Pos(SubStr, Str) ... где Str - строка, в которой производится поиск SubStr. Функция возвращает позицию вхождения в качестве результата. Если строка SubStr не находится в Str, то результат выполнения функции будет равен 0. Функция различает регистр букв - большой и маленький, т.е. подстрока 'dancing' будет найдена в 'We dancing in shadows', но не будет найдена в 'We Dancing In Shadows'.
Пример использования Pos:Должно быть напечатано число 16.
program StringDemo07; {$APPTYPE CONSOLE} var I:Integer; begin I:=Pos('win','Good guys only win in movies'); WriteLn(I); ReadLn; end;
Изменение регистра символов
Каждый символ, представляющий собой букву, имеет регистр - верхний или нижний. Например, буква "а" может быть заглавной "А" и прописной "а". Заметим что "А" и "а" являются различными символами. Про заглавные буквы говорят, что они имеют верхний регистр. Про прописные буквы говорят, что они имеют нижний регистр. В некоторых случаях нужно преобразовать отдельную строку или символ в верхний или нижний регистр. Это делают функции 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 значение SourceString переведенное в нижний регистр TargetString:=LowerCase(SourceString); // напечатаем содержимое TargetString WriteLn(TargetString); // напечатаем значение SourceString переведенное в верхний регистр WriteLn(UpperCase(SourceString)); // Возведем первый символ TargetString в верхний регистр TargetString[1]:=UpCase(TargetString[1]); // возведем последний символ TargetString в верхний регистр TargetString[Length(TargetString)]:=UpCase(TargetString[Length(TargetString)]); // напечатаем содержимое TargetString WriteLn(TargetString); // понизим регистр первого символа TargetString TargetString[1]:=LoCase(TargetString[1]); // напечатаем содержимое TargetString WriteLn(TargetString); // Ждем нажатия Enter 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