И все было хорошо, пока вирусная атака не уничтожила бесценную программу. А где распечатка исходника? Увы, к тому времени её погрызли мыши! Друзья, теперь надежда только на вас, выручайте школу!
С первого взгляда на задачу ясно: входной файл надо обрабатывать построчно, выбирая из каждой строки данные двух типов: строковые – фамилии учеников, и числа – их оценки. Это не так просто, как может показаться, а потому решать задачу будем в два счёта. На первом этапе упростим её, оставив во входном файле лишь оценки учеников, а полное решение отложим до следующей главы. Входной файл без фамилий будет теперь таким.
3 5 4
5 5 5 5
4 5 5 4
3 4 3
4 3
А в результате обработки мы должны получить такой выходной файл.
Номер Количество Сумма Средний
оценок баллов балл
1 3 12 4.0
2 4 20 5.0
3 4 18 4.5
4 3 10 3.3
5 2 7 3.5
Набросаем план предстоящего сражения, то есть блок-схемы алгоритмов. На рис. 68 показан алгоритм главной программы. Он очень похож на тот, что применялся при шифровании текста, и это объяснимо: и там, и здесь выполняется построчная обработка файла.
Рванув со старта, программа открывает входной файл, создает выходной и пишет туда заголовок таблицы – так называемую шапку. По окончании обработки оба файла будут закрыты. В этом алгоритме предусмотрен также и подсчет строк входного файла, необходимый для нумерации учеников в выходном файле.
Разобравшись с главной программой, сосредоточимся на обработке отдельной строки. Здесь заметно сходство со вторым вариантом полицейской базы данных (глава 29). И там, и тут читается ряд чисел, размещенных в одной строке. Но если в полицейской программе нам было безразлично, где кончается строка, то теперь иное дело, – ведь на следующей строке расположены оценки другого ученика! Нужен признак, сообщающий о достижении конца читаемой строки. Где его взять?
Ну, вы же понимаете, – в Паскале предусмотрено все! Познакомьтесь с функцией булевого типа по имени EoLn (от английского End of Line, что значит «конец строки»). Заголовок этой функции выглядит так:
function Eoln(var aFile: text): boolean;
Функция принимает параметр – ссылку на текстовый файл – и возвращает TRUE, если позиция чтения в этом файле достигла конца строки. Она похожа на функцию Eof, проверяющую достижение конца файла. Исследуем функцию следующей программкой.
{----- Программа для исследование функции Eoln -----}
var F: text; N: integer;
begin
Assign(F, 'Police.txt'); Reset(F);
while not Eof(F) do begin
Read(F, N); { чтение числа }
Writeln(N, ' -- ',
end;
Close(F); Readln;
end.
Здесь из файла «Police.txt» читаются все числа, при этом печатаются и сами числа, и признак конца строки. Предположим, файл «Police.txt» содержал такие строки.
1 2 3
10 20 30
100 200 300
Тогда на экране явится вот что.
1 -- FALSE
2 -- FALSE
3 -- TRUE
10 -- FALSE
20 -- FALSE
30 -- TRUE
100 -- FALSE
200 -- FALSE
300 -- TRUE
Как видите, после чтения последнего числа в строке признак её окончания равен TRUE.
Теперь, когда мы нащупали конец строки, соорудим алгоритм обработки одной строчки входного файла (рис. 69).
Основу алгоритма составляет цикл чтения чисел, в ходе которого наращиваются счетчик оценок и их сумма. На входе в цикл и счетчик, и сумма очищаются, то есть, загружаются нулями. Выход из цикла происходит при достижении конца строки, и тогда в бой вступает условный оператор. Он исследует счетчик оценок, и, если оценок в строке не было, выводит в выходной файл сообщение «ученик не аттестован», а иначе печатает средний балл.
Кстати, годится ли для чтения строки оператор цикла REPEAT-UNTIL? Правильный ответ – нет. Если текущая строка окажется пустой, следующая оценка прочитается уже на следующей строке, а это не то, что нам нужно! Оператор WHILE – единственно правильное решение.