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

[ Миронченко ] Императивное и объектно-ориентированное програмирование на Turbo Pascal и Delphi

.pdf
Скачиваний:
69
Добавлен:
25.04.2014
Размер:
3.16 Mб
Скачать

191

20:for i:=1 to h do

21:Umdrehung[i]:=st[h+1-i];

22:Umdrehung[0]:=chr(h);

23:end;

24:

25:function ZeilUpCase (const st:string):string;

26:var

27:i:byte;

28:begin

29:for i:=1 to length(st) do

30:ZeilUpCase[i]:=UpCase(st[i]);

31:end;

32:

33:function IstKorrekt (const st:string):boolean;

34:var

35:h,i:byte;

36:n:integer; {n - разность между количеством открывающих}

37:{и закрывающих скобок}

38:begin

39:h:=length(st);

40:n:=0;

41:for i:=1 to h do

42:begin

43:if st[i]=')' then {разность стала на один меньше}

44:dec(n);

45:if st[i]='(' then {разность стала на один больше}

46:inc(n);

47:

if n<0 then

{Если кол-во закр. скобок стало больше числа}

48:

begin

{открывающих, то скобки расставлены неверно}

49:IstKorrekt:=false;

50:exit;

51:end;

52:end;

53:

if n=0 then

{Если кол-во откр. скобок = числу закр., то }

54:IstKorrekt:=true {строка - верна}

55:else

56:IstKorrekt:=false;

57:end;

58:end.

Далее – основная программа

1 : uses ZeilenU;

2 : var

3 : str1,str2:string;

4 : begin

5 : read(str1);

6 : str2:=Umdrehung(str1);{Переворачиваем строку str1}

7 : writeln;

8 : writeln(str2);

9 : str2:=ZeilUpCase(str2);{Переводим str2 в верхний регистр} 10: writeln(str2);

11:

192

12:str1:='Mathematiker';

13:str2:=' und Programmierer';

14:str1:=str1+str2; {Mathematiker und Programmierer}

15:writeln(str1);

16:

17:str2:='Sie sind ';

18:Insert(str2,str1,1); {Sie sind Mathematiker und Programmierer}

19:writeln(str1);

20:Delete(str1,5,10);

21:writeln(str1);

22:

23:str1:='((ddd)dddd(';

24:writeln(str1,' ',IstKorrekt(str1)); {false}

25:str1:='(ddd) sss (hh)';

26:writeln(str1,' ',IstKorrekt(str1)); {true}

27:readln;

28:end.

Принцип проверки строки на правильность расстановки одного типа скобок прост: в специальной переменной хранится разность между количеством открытых и закрытых скобок. Если на каком-то символе это число станет <0, то скобки расставлены неверно. В противном случае скобки расставлены правильно.

Мы написали процедуру, проверяющую правильность расстановки скобок. Но скобки могут быть разных типов: (), {}, [], “”, ‘’ и т.д. Нашей целью теперь станет проверить правильность расстановки нескольких типов скобок. Просто проверить на правильность расстановки каждую из них по очереди нельзя: это еще не гарантирует правильность написания строки (пример такой строки: « (ааа{ffff)} »). Следовательно, воспользоваться предыдущей процедурой нельзя – хотя она и выглядит красиво и миниатюрно, но она не может стать основой для более общего алгоритма.

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

Пример 3: Проверка правильности расстановки нескольких типов скобок.

1

: const

2

:

n=3;

3

: type

4

:

Klammern = array [1..n,1..2] of char; {Klammer = скобка}

5

:

 

6

: { k=1 =>Проверяет, явл. ли символ с открывающей скобкой }

7

: { k=2 =>Проверяет, явл. ли символ с закрывающей скобкой }

8

: function IstKlammer(c:char;k:byte;var D:Klammern):byte;

9

: var

10:j:byte;

11:begin

12:for j:=1 to n do

13:if (c=D[j,k]) then

193

14:begin

15:IstKlammer:=j;

16:exit;

17:end;

18:IstKlammer:=0;

19:end;

20:

21:function IstKorrekt(const s:string;var Divis:Klammern):boolean;

22:var

23:Stapel:array [1..255] of byte; {Stapel = стек}

24:KlQuant:byte; {Klammern Quantitat = количество скобок}

25:i,indB:byte;

26:begin

27:KlQuant:=0;

28:i:=1;

29:while i<=length(s) do

30:begin

31:indB:=IstKlammer(s[i],1,Divis);{Является ли открывающей ск.}

32:if indB<>0 then

33:begin

34:inc(KlQuant); {Увеличиваем количество открытых скобок}

35:Stapel[KlQuant]:=i;{Заносим индекс скобки в стек}

36:inc(i);

37:continue;

38:end;

39:indB:=IstKlammer(s[i],2,Divis);{Является ли закрывающей ск.}

40:if indB<>0 then {Нашли закрывающую скобку}

41:begin

42:if KlQuant=0 then{Если открывающих нет}

43:begin

44:IstKorrekt:=false;

45:exit;

46:end;

47:if (Divis[indB,1]=s[Stapel[KlQuant]]) then{Если скобка

подходит}

48:dec(KlQuant){уменьшаем кол-во открытых скобок в стеке}

49:else

50:begin

51:IstKorrekt:=false;

52:exit;

53:end;

54:end;

55:inc(i);

56:end;

57:

58:if KlQuant=0 then {Если скобок нет}

59:begin

60:IstKorrekt:=true;

61:exit;

62:end;

63:IstKorrekt:=false;

64:end;

194

65:

66:var

67:s:string;

68:const

69:D:Klammern=(('{','}'),('(',')'),('[',']'));{типизир.

константа}

70:begin

71:writeln('Введите строку:');

72:readln(s);

73:writeln(IstKorrekt(s,D));

74:readln;

75:end.

Встроке 69 объявлена типизированная константа (ТК) типа Divisors. ТК – это на самом деле переменная, которая инициализирована начальным значением. Чтобы объявить ТК простого типа (числа, символы, строки, булевский тип), например, целого, надо записать так:

const a:integer = 5;

Чтобы сделать массив A из четырех вещественных чисел типизированной константой, надо перечислить элементы, заключив их в скобки:

A:array[1..4] of real = (1.2, 2.3, 3.4, 4.1)

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

Если типом является запись, то надо в скобках перечислить значения каждого из полей.

Как внести в строку символы, которые нельзя написать на клавиатуре

Для того чтобы вставить в строку спец. символы, вы можете использовать функцию chr, которая по коду вернет вам любой символ из набора символов ASCII, или использовать машинные коды. Чтобы получить символ с нужным машинным кодом, надо набрать символ #, а затем – число.

Пример 4: Использование машинных кодов для написания спец. символов. begin

write('Привет! '+#13#10+'А это - другая строка'); write(chr(65)+chr(66));

readln;

end.

Результат работы этой программы такой: Привет!

А это – другая строка АВ

195

Задачи

1.Дан массив символов. Надо все символы ‘w’, встречающиеся в строке заменить пробелами.

2.Сосчитать количество слов в массиве символов (слово – последовательность символов, перед которой и после которой стоит пробел).

3.Дан массив символов из 26 элементов. Случайным образом заполнить все его элементы строчными буквами латинского алфавита.

4.Дан массив символов из 26 элементов. Случайным образом заполнить все его элементы строчными буквами латинского алфавита так, чтобы ни одна из букв не повторялась дважды.

5.Дан массив символов. Проверить, можно ли из букв этого массива построить заданное слово. Буквы из массива могут использоваться лишь по одному разу. Например, из слова “Математик” слово “мама” составить можно, а слово «папа» нельзя.

6.Дана строка. Сосчитать количество пробелов в ней.

7.Дана строка. Если в строке будет идти подряд несколько одинаковых символов, то надо удалить все, кроме одного.

8.Дана строка. Найти в ней все слова, начинающиеся с буквы а, и вывести их на экран.

9.Дана строка. Найти количество различных символов в ней.

10.Дан массив строк. Каждая строка – английское слово. Требуется отсортировать этот массив в алфавитном порядке.

11.Проверить, является ли введенная фраза палиндромом, без учета пробелов (например, «Аргентина манит негра»).

12.Вам дана строка, в которой написано целое число. Вы должны записать в переменную типа longint число, записанное в строке.

13.Напишите программу, единственным действием которой было бы очистить экран и напечатать на дисплей саму себя (т.е. программный код). Использовать файл с исходным кодом нельзя.

196

Глава 12: Файлы

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

12.1.Логические и физические файлы.

ВТР есть 2 типа файлов: логические и физические.

Физический файл – именованная область энергонезависимой памяти.

Каталог – системный файл, поддерживающий структуру ФС.

Кфизическим файлам, кроме «обыкновенных» файлов, в которых хранятся данные, относятся некоторые устройства, например: принтер, клавиатура.

Логические файлы – это переменные одного из файловых типов ТР.

Всего таких типов 3:

Текстовые файлы (типа Text);

Типизированные файлы (типа File of <некоторый тип данных>)

Бестиповые файлы (типа File)

Текстовые файлы состоят из кодов ASCII, включая управляющие и расширенные

коды.

Знак конца строки – символ с кодом 13 (#13). Знак перевода строки – символ с кодом 10 (#10). Знак конца файла – символ с кодом 26 (#26).

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

Типизированные файлы состоят из машинных представлений того типа данных, который стоял в заголовке описания файловой переменной. Бестиповые файлы тоже состоят из машинных представлений данных, но их тип не определен заранее и в них можно комбинировать данные разных типов.

12.2. Открытие и закрытие файлов.

Прежде, чем начать работу с физическим файлом, надо связать его с каким-то логическим файлом.

Это можно сделать с помощью процедуры assign(var f; path:string); f – переменная любого файлового типа,

path – путь к физическому файлу. Например:

assign(f,'C:\Programmierung\smth.pas');

Если файл находится в текущем каталоге, то весь пусть к файлу можно не указывать, например:

assign(f,'aaa.txt');

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

197

Rewrite(var f), где f – некоторый логический файл, создает файл f и открывает его для записи данных.

Reset(var f) открывает файл для чтения данных (но не создает его!).

Close(var f) закрывает открытый ранее файл. Если процедуру close вызвать для уже закрытого файла, то произойдет ошибка в программе.

12.3. Текстовые файлы

Пример 1: Программа, позволяющая записать несколько строк в файл.

1 : var

2 : f:Text;

3 : s:string;

4 : begin

5 : assign(f,'file1.txt');{связываем файл f c физическим файлом} 6 : rewrite(f);{открываем f}

7 : repeat

8 : readln(s);

9 : if s='' then {Пустые строки не печатаем}

10:break;

11:writeln(f,s);{записываем в файл f строку s}

12:until s='';{пока не будет введена пустая строка}

13:close(f);{если файл не закрыть, то данные потеряются}

14:end.

Вэтой программе вы будете вводить строки в файл, а они будут выводиться в файл 'file1.txt'. Ввод прекратится, как только вы введете пустую строку.

Запись строк в файл производится с помощью знакомых нам процедур write и writeln. Компилятор анализирует первый аргумент функции, и если это типизированный или текстовый файл, то он понимает, что все последующие аргументы надо записывать в файл f. Абсолютно аналогичные свойства у процедур read и readln.

Пример 2: Создание файлов, в которых хранятся массивы чисел.

1 : const

2 : n=15;

3 : var

4 : f,f2:Text;

5 : M:array[1..n] of real;

6 : i:integer;

7 : x:real;

8 : begin

9 : assign(f,'file2.txt');{связываем файл f c физическим файлом}

10:rewrite(f);{открываем f}

11:for i:=1 to n do {заполняем файл случайными числами}

12:writeln(f,random*100);

13:assign(f2,'file22.txt');

14:rewrite(f2);{открываем f2}

15:reset(f);{открываем f для чтения}

16:for i:=1 to n do {заполняем массив числами из файла}

17:readln(f,M[i]);

18:for i:=n downto 1 do{заполняем числами файл f2}

198

19:writeln(f2,M[i]);

20:close(f);{А сейчас закрыть оба файла надо обязательно}

21:close(f2);

22:end.

Как видите, в строке 10 файл f открывается для записи, а в строке 15 открывается для чтения. Когда вы работаете с файлами, вы можете сколько угодно раз открывать их для чтения или записи, не закрывая их при этом. Однако в конце работы программы все открытые файлы должны быть обязательно закрыты.

Для того, чтобы добавлять информацию в конец файла (существующего), не стирая содержащейся в ней до этого информации, есть специальная процедура:

Append(var f:Text)

Пример 3: Добавление строк в текстовый файл.

1 : var

2 : f:Text;

3 : s:string;

4 : begin

5 : assign(f,'file1.txt');{связываем файл f c физическим файлом} 6 : append(f);{открываем f для дозаписи}

7 : repeat

8 : readln(s);

9 : writeln(f,s);{записываем в файл f строку s}

10:until s='';{пока не будет введена пустая строка}

11:close(f);{если файл не закрыть, то данные потеряются}

12:end.

Эта программа ничем не отличается от примера №1, кроме строки №6 (вместо процедуры Rewrite используется Append).

В примере №2 мы читали из файла массив чисел. Но при этом мы считывали заранее известное количество чисел. Но ведь обычно заранее не известно, сколько чисел или символов в файле; в таких случаях надо знать, когда заканчивать чтение информации из файла. Для такой цели есть специальная функция EOF(var f) (EOF – сокращение End Of File), которая возвращает true, если достигнут конец файла, а false – в противном случае.

Для текстовых файлов есть еще одна полезная функция – Eoln(var f:Text), возвращающая true, если достигнут конец строки, false – в противном случае.

12.4. Типизированные файлы

Если вы хоть раз посмотрели в файлы, с которыми мы работали в примерах 1..3, то вы поняли, что писать в текстовый файл – то же самое, что печатать просто на экран: если вы записываете в файл переменную х, в которой хранится число 112, то и в файле запишется «112», если пишете переменную а, в которой хранится строка ‘Anders’, то и в файле будет написано Anders.

При работе с типизированными файлами принцип другой: если вы печатаете значение переменной, то в файл будет занесена та информация, которая хранится в памяти под именем вашей переменной. Давайте рассмотрим простой пример, чтобы вы все хорошо поняли.

199

Пример 4: Типизированный файл из целых чисел.

1 : var

2 : f:file of integer;

3 : i:integer;

4 : begin

5 : assign(f,'fileInt.txt');

6 : rewrite(f);

7 : for i:=24897 to 24897+4 do

8 : write(f,i);

9 : close(f); 10: end.

Итак, мы хотим создать file of integer, и записать туда 5 чисел: 24897, 24898,

24899, 24900, 24901.

Переменная integer содержит 2 байта, поэтому на любое число типа integer в file of integer будет отводиться 2 байта. Давайте подсчитаем, что нам запишет компьютер в файл. Двоичное представление числа 24897 такое: 01100001 01000001. Т.е. в старшем байте находится число 01100001 (в десятичной ССч 97), а в младшем – 01000001 (в десятичной ССч 65). При записи в типизированный файл ПК каждый байт интерпретирует как символ, и записывает ASCII-код, соответствующий числу, которое в байте хранится. Числу 1 соответствует символ «а», а числу 65 – символ «А».

Кроме того, в переменной, которая содержит 2 байта, младший и старший байты хранятся в обратном порядке (вы уже сталкивались с этим в главе «Матрицы»). В итоге получим, что представление числа 24897 будет таким: Аа.

А все 5 чисел запишутся в файле так: АаBaCaDaEa.

Если вам надо прочитать из file of integer несколько чисел, то компьютер будет извлекать по 2 символа, и переводить их в соответствующее число.

Какие можно сделать выводы:

В типизированных файлах очень экономно хранятся числа.

Читать типизированные файлы можно, лишь если вы знаете, какого типа информация в нем хранится (т.е. знаете формат файла), и как хранится эта информация в ПК.

12.5. Последовательный и прямой доступ к файлам

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

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

Для перехода к нужной позиции в файле, используется процедура Seek(var f;N: longint)

200

f – логический файл (не текстовый), N – номер позиции. Если надо работать с х-той записью, то надо указать N=x-1.

Другие полезные процедуры:

function FilePos(var f):longint

Возвращает номер текущей позиции в файле.

function FileSize(var f):longint

Возвращает кол-во записей в файле

Пример 5: Позиционирование в типизированном файле. type

Etwas=record {Etwas – что-то} x,y:real;

s:string[10];

end; var

X:Etwas;

f:file of Etwas;{Файл с записями типа Etwas} i:integer;

begin assign(f,'etw.dat');

rewrite(f); {открываем для записи} for i:=1 to 4 do

begin X.x:=random; X.y:=random;

writeln('Введите строку (до 9 символов): '); readln(X.s);

write(f,X); {Записываем в файл} end;

close(f);

reset(f);{Открываем для чтения}

while not(eof(f)) do {пока не достигнут конец файла} begin

read(f,X); {считываем запись} writeln(X.x,' ',X.y,' ',X.s); end;

seek(f,2);{Готовимся работать с 3-ей записью} read(f,X);{Cчитываем 3-ю запись} writeln('печатаем 3-ю запись');

writeln(X.x,' ',X.y,' ',X.s); close(f);

end.

12.6. Буфер ввода/вывода

Прежде чем записать данные в файл или прочесть их оттуда, информация поступает в буфер – специальную область памяти, которая выделяется при открытии файла. Если надо записывать данные в файл, то информация накапливается в буфере, пока он не заполнится. Лишь затем данные записываются в файл. Считывать за 1 раз нельзя объем, превышающий размер буфера. По умолчанию размер буфера равен 128 байт; менять его размер для текстового файла можно с помощью процедуры

SetTextBuf(var f:Text;var Buf [BufSize:word]);