Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Самоучитель игры на Паскале. АВС и немного Турбо

.pdf
Скачиваний:
0
Добавлен:
07.09.2026
Размер:
1 Мб
Скачать
Глава 6.
Строки
Просто строка
Знаменательное событие. Было у нас два типа данных – целые и дробные, integer и real, будет три. По-русски – строка, по-программистски – string.
Как там, в сказке – было у старика три сына, двое умных, третий дурак. Короче, не совсем похожий на предыдущие типы. По сути, замаскированный массив.
На самом деле, массив он и есть, и даже вовсе не замаскированный.
Теперь как всегда – объявить переменную типа строка, присвоить что­нибудь переменной типа строка, вывести переменную типа строка. Поехали.
var s : string;
Переменной цикла принято давать имя I, массив часто называют A, у строки обычная кличка – S. Набрав слово string без ошибок, обнаружим, что оно выделено полужирным шрифтом, то есть тоже относится к разряду волшебных зарезервированных слов, в отличие от integer и re
му – тайна.
Поче
Присваиваем: S:= ‘woodpecker’;
Напоминаем для озабоченных – если хочется, чтобы внутри строки была кавычка, надо вместо одной поставить две, вот так: ‘wood’’pecker’. Максимальная длина строки – 255 символов.
Для любознательных. Строку можно объявить вот так, например: s : string[30]; Максимальная длина такой строки не 255, а только 30 символов. Зачем это надо? Если очень хочется сэкономить оперативную память. Под просто string
выделяется 256 байтов, а под string[30] будет выделен 31 байт. Почему не тридцать? Для пытливых умов. Есть ещё нулевой байт, s[0]. В нем хранится фактическая длина строки. То есть по s:=’abcd’; значение нулево Для любителей совать пальцы в розетку. Во времена Паскаля некоторые, чтобы узнать длину строки, вместо Length(s) предпочитали писать Ord(s[0]). Ещё чаше, при необходимости оставить от строки, например, первые десять символов,
го байта будет равно четырем.
al.
сле оператора
101
писали s[0]:=Chr(10); И всё, в общем-то, у некоторых работало. И даже под Delphi работало. И как же эти некоторые огребли при переходе на Delphi 2… А что такое Ord и Chr, разузнайте сами. Потом, конечно, я расскажу. Если кто-то сомневается, стоит ли экономить жалкие байты на такой ерунде, то задумайтесь – а если таких строк у вас миллион?
Если у нас есть две целые переменные, то мы можем поставить между ними знак арифметической операции и результат присвоить третьей целой переменной. Для дробных чисел всё так же, только операции немного другие. А для строк?
var s1,s2,s3 : string;
begin
ClrScr; s1:=’123 ‘; s2:=’abcd ‘; s3:=s1 + s2; Writeln(s3);
Получим на экране
123 abcd
С плюсом разобрались – он склеивает две строки в од
ну. А ещё? А всё! Больше операторов не предусмотрено. Почти. Придётся идти другим путём.
Просто строка и её процедуры
Ну не совсем её процедуры. Скорее процедуры для неё. И не совсем процедуры. Скорее функции. Но неважно. Сейчас перейдём к конкретике, и всё будет по Функция Length. Не очень ин
нятно. Более-менее.
тересная, но самая важная. Поскольку это функция, вроде Sin, то она возвращает значение, которое можно прис
воить переменной. Только у Sin значение дробное, а у Length целое.
Пишем вот такое:
var
102
s : string; len : integer;
begin
ClrScr; s:=’12345’; len:=Length(S); Writeln(len);
Видим на экране цифру пять. Путём несложных умственных усилий приходим к немудрёному выводу, что функция Length возвращает нам количество символов в строке. А почему она самая важная? А это станет ясно в следующем разделе. Кстати, помните, что кавычка внутри строки кодируется двумя идущими подряд кавычками? В подсчёте симв следовало ожид А пока – функция Copy.
s1:=’12345’; s2:=Copy(S, 2, 3); Writeln(s2);
В результате имеем 234. Copy выкусывает из строки часть, начинающуюся с символа имеющего номер, указываемый вторым параметром и в количестве символов, которое задает третий параметр. Обратите внимание, что эта функция в качестве результата возвращает не число, а строку. А теперь функция Pos. Она во поисками одной строки в другой. Вот так:
s1:=’12345’; where:=Pos(‘
После выполнения where будет равно, разумеется, двум. А если искать в строке что-нибудь эдакое, чего в ней нет, то в результате получим, как принято, ноль. Ещё совершенно необходимая – не функция – процедура Delete.
ать, идут за одну.
2’, s1);
олов эти две кавычки, как и
звращает целое число и занимается
103
s1:=’12345’ Delete( s1, 3,2);
В результате в s1 останется только 125. Двойка в параметрах говорит, что из исходной строки надо удалить два символа, а тройка – что удалять символы надо, начиная с третьей позиции в строке. Если что-то можно удалить, то обычно где-то рядом должна быть и возможность обратного процесса. И вот она – по параметра – что вставить,
s1:=’12345’; s2:=’abc’; Insert( s2, s1, 3); Writeln(s1);
Получим 12abc345. Вот и вся компания. Применяется этот зоопарк обычно не по одному, а в совокупности.
s1:=’x=f(y)’; s2:=’z=x’;
Задачаподставить во вторую строку значение X из первой.
s3:=s2; Delete( s3, Pos(‘=’,s2)+1, 999); Insert( Copy(s1,Pos(‘=’,s1)+1,999), s3, Pos(‘=’,s3)+1);
В результате в s3 должны получить
‘z=f(y)’;
Магическое число 999 означает, что мы имеем в виду все си конца строки. Copy и Delete, если третий параметр больше, чем в строке
ось символов, понимают его, как количество символов до конца
остал строки.
куда, в какое место. То есть:
д названием Insert. Три
мволы до
104
Строка и цикл
С помощью процедур из предыдущего раздела и циклов можно решить любую задачу обработки строк, хотя часто и несколько противоестественным способом. Например, надо подсчитать количество пробелов в строке. В цикле – находим пробел с помощью Pos, увеличиваем счётчик, удаляем пробел с помощью Delete, снова находим пробел… И так будем продолжать, пока строка не кончится. Цикл, правда, нужен не задача решаема, по-другому – просто берём и считаем. Можно так? А как же. Идея в том, что со строкой можно обращаться в точности, как с массивом. Ну, почти. Например: s[5]:=’a’; - в пятом символе строки ‘a‘. Аналогично if s[5]=’b’ – проверяем – а не равняется ли случайно пятый символ строки символу ‘b’?
Если мы написали s:=’12345’; то у нас в строке ровно пять символов. Мы можем обращаться к символам от первого до пятого, но не более того. Нельзя написать s[6]:=’6’, это плохо ко
‘6’;
А теперь, вооружённые но все символы строки от первого до последнего. Проверяем – если пробел, значит сосчитали. Пишем цикл. От первого символа – это понятно. До последнего символа – вспоминаем функцию Length. Как проверять на равенство пробелу, только что познакомились. В результате имеем:
num:=0; for i:=1 to Length(s) do begin if s[i]= ‘ ‘ th end;
А теперь задача – подсчитать, сколько раз в строке встречается оп проверять надо не только текущий символ, но и два последующих. Если
много другой, об этом ещё будет позже. Потом. В любом случае,
но в жизни подсчёт пробелов в строке решается совсем
будет символ
нчится. Надо так s:=s +
выми знаниями, считаем пробелы.. Перебираем
en num:=num + 1;
ределенный артикль ‘the’. Задача похожа на только что решённую, но
105
текущий символ имеет индекс I, то у следующего будет индекс I+1, а у того, что после этого I+2. В целом получится что-то вроде:
num:=0; for i:=1 to Length(s) do begin if (s[i]= ‘t‘) and (s[i+1]=’h’) and (s[i+2]=’e’) then num:=num + 1; end;
Почему “что-то вроде”? Потому что когда переменная цикла I будет указывать на последний символ строки (Length(s)), мы попытаемся проверить ещё и сл получится. А с другой стороны – разве мож
едующий символ (I+1) и ничего хорошего из этого не
ет слово из трех букв начинаться в последнем символе строки – ясно, что нет, ведь не уместится же. Не может начинаться и в предпоследней, по той же причине (так что рухнет наша программа ещё раньше, при I, равном Length(s))-1). А раз оно там начинаться не может, так зачем
проверять? Урезаем цикл на два
исполнения:
num:=0; for i:=1 to Length(s)-2 do begin if (s[i]= ‘t‘) and (s[i+1]=’h’) and (s[i+2]=’e’) then num:=num + 1; end;
Может, у кого-то затесалась в голову мыслишка, что, ежели мы обнаружили слово “the”, начинающееся с позиции I, то проверять следующие две позиции на наличие символа ‘t’ – пустое расточительство? Немедленно топтать мыслишку коваными сапогами. Нам не надо, как лучше – нам надо чтоб работало. Работает – отойди, не трогай.
На самом деле при таком подходе мы сосчитаем и все слова типа then, содержащие внутри себя последовательность символов the, но не будем обращать внимание на такие мелочи. Пока.
Помните, как считается сумма элементов массива?
sum:=0; for i:=1 to N do sum:=sum + a[i];
106
У строки ведь тоже есть оператор “+”, хотя он выполняет не арифметическое сложение, а склейку строк. Простая задача – заполнить строку одним и тем же символом, например ‘-’. Всё аналогично. В начале цикла целой переменной присваивается значение ноль. А что будет аналогом ноля для строки? Пустая строка, то есть строка, в которой нет ни
ого символа. Обозначается это чудо вот так ‘’ – две кавычки подряд,
одн без проб И вот текст программы:
s:=’’; for i:=1 to N do s:=s + ‘-‘;
Обратите внимание, мы заполнили строку, в которой до того не было ничего. Если мы хотим заполнить каким то символом строку из предыдущего примера, то есть уже заполненную, то выглядеть это бу так:
for i:=1 to Length(s) do s[i]:=‘*‘;
Очень похоже на м А теперь ещё две задачи, которые в разных вариациях будут встречаться весьма часто. Удалить из строки (например, ‘123 456 789’) все пробелы. Напрашивается быстрая модификация недавно созданной программы:
s:=’123 456 789’; for i:=1 to Length(s) do begin if s[i]= ‘ ‘ then Delete( s, i, 1); end;
В результате имеем на вых вредности подсовываем на вх группами по два пробела). Результат – ‘123 456 789’. Что-то не так, пробелы уменьшились в количестве, но всё-таки остались. Почему? Очень
ела между ними.
дет
ассив. Обдумайте.
оде: ‘123456789’. Замечательно! А теперь из
од вот такую строку – ‘123 456 789’ (между
107
просто. Сначала проверили четвёртый символ, потом пятый. Четвертый оказался пробелом, его удалили. Но при этом вся остальная часть строки сдвинулась влево и нумерация оставшихся символов изменилась. Следующий пробел, бывший пятый, стал четвёртым. Но четвёртый символ мы уже проверили и переходим к пятому, а туда съехала цифра 4 из бывшей шестой позиции. Вот так всё не будем? Если мы начнём просматривать строку с конца к началу, то, удалив первый встреченный пробел (последний в строке), мы изменим нумерацию всех символов справа, но там-то мы уже были. А с символами слева, куда мы и направляемся, всё останется в порядке.
s:=’123 456 789’; for i:=L if s[i]= ‘ ‘ then Delete( s, i, 1); end;
Если у нас цикл движется от большего значения к меньшему, то, вместо to должно использоваться downto. Запомните – удаление чего-то из чего-то пронумерованного обычно происходит, начиная с конца этого второго чего-то. Такое ненарушаемое правило.
А теперь задача - подсчитать количество слов в строке. Количе пробелов между словами – произвольное, то же с пробелами в конце строки, так что идея просто подсчитать пробелы нас к решению не приблизит. Задача это встречается чаще, чем кажется с первого взгляда. Но сначала придётся отвлечься и мимоходом ввести ещё один тип данных. Тянул я с этим до последнего.
ength(s) do
wnto 1 do begin
Ой, кто пришел!
удачно получило
сь. Что делать
ство
начале и в
Встречаем – логические переменные, они же булевские. Зачем нужны? Да незаче то, излишняя сущность. Гвозди вполне можно и топором заколачивать. В переводе на программирование – забываем про булевский тип, объявляем целую переменную и договариваемся, что будем присваивать ей строго
108
м, как обычно. Вполне можно обойтись. Молоток, он, в общем-
только ноль или единицу. Причем, опять же для себя, решаем, что ноль значит “нет”, единица значит “да”. Да ведь мы это уже делали – когда сортировали массив! А теперь ещё раз, проиллюстрируем на другом примере. Хотелось бы знать – а не состоит ли наша строка полностью, только, и исключительно из одних пробелов? Вопро как мы считали пробелы в строке, можно додуматься до такого варианта: подсчитать пробелы в строке и, если их количество совпадет с длиной строки – то да. А если нет – то нет.
num:=0; for i:=1 to Length(s) do begin if (s[i]= ‘ ‘) then num:=num + 1;
end; if num=Length(s)
then Writeln(‘Yes!’) else Writeln(‘No!);
Работает, конечно. Но как-то неизящно. И зачем дел Зачем сч нас же никто про это не спрашивал. Вопрос был – да или нет? Пишем вот так (onlySpaces, понятно, целое и означает, что строка только из пробелов):
onlySpaces:=1; for i:=1 to Length(s) do begin if (s[i]<> ‘ ‘) then onlySpaces:=0;
end; if onlySpaces = 1
then Writeln(‘Yes!’) else W
А теперь доведём наш шедевр до по переменными. Сначала теория, разумеется. Объявляем:
var
итать пробелы и помнить (до условного оператора) сколько их? У
riteln(‘No!);
с очень реальный. Вспо
ать лишнюю работу?
лного блеска булевскими
мнив,
109
onlySpaces : boolean;
Булевская переменная может получить только два значения:
onlySpaces:=true; { да} или onlySpaces:=false; {нет}
Использовать её в условном операторе можно как обычно:
if onlySpaces = true { да} или if onlySpaces = false {нет}.
Но так никогда не пишут, поскольку ради булевских переменных разрешена, для наглядности, сокращённая форма записи:
if onlySpaces { да} или if not onlySpaces {нет}.
Окончательный вариант (onlyS
onlySpaces:=true; for i:=1 to Lengt if (s[i]<> ‘ ‘) then onlySpaces:=false; end; if onlySpaces then Writeln(‘Yes!’) else Writeln(‘No!);
Обратите внимание – это важно! Если нам надо определить, есть ли в строке хоть один пробел (для умных – квантор существования), то признак перед началом цикла устанавливается в ложь (false), а при встрече первого пробела устанавливается в истину (true). Напротив, если надо опред
ости), то символ устанавливается перед циклом в истину, а при
общн встрече первого не пробела устанавливается в ложь.
h(s) do begin
елить, все ли символы в строке пробелы (для умныхквантор
paces объявлено как boolean):
110
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]