Книга: Песни о Паскале
Глава 31 Финал журнальной истории
Разделы на этой странице:
Глава 31
Финал журнальной истории
В предыдущей главе мы поклялись восстановить съеденную мышами программу и отчасти сдержали клятву. Нами решена упрощенная задача – обработка журнала без фамилий учеников, то есть, мы исполнили вычислительную часть проекта. Теперь завершим его, добившись обработки настоящего классного журнала. Требуется, казалось бы, пустяк – прочесть фамилии учеников. Но воспользоваться процедурой Readln, как мы поступили в программе шифрования текста, здесь не получится, – она прочитает всю строку целиком, включая и оценки (которые станут как бы частью фамилии!).
Буква за буквой
Славный литературный герой Остап Бендер по поводу желанного миллиона сказал так: «Я бы взял частями, но мне нужно сразу!». Увы! При чтении фамилий надо проявить терпение. Если не получается сразу, возьмем по частям. Ведь строка фамилии состоит из отдельных букв, – так прочитаем фамилию по буквам! Прочитать букву может все та же процедура Read, например:
var sym : char;
...
Read(InFile, sym); { чтение одного символа }
А фамилию S склеим из отдельных букв:
S:= S + sym;
Разумеется, что здесь нужен цикл, условием выхода из которого будет либо достижение первого пробела, либо достижение конца строки. В этом и состоит основная идея алгоритма, показанного на рис. 71.
Рис.71 – Упрощенный алгоритм побуквенного чтения фамилии
Нелишняя предосторожность
Людям свойственно ошибаться, – даже учителям! В строках журнала (а это текстовый файл) могут оказаться лишние пробелы – как между оценками, так и в начале строки, перед фамилией. И что тогда? – проверьте на практике. При чтении чисел процедура Read «не заметит» лишних пробелов, – она достаточно «умна». Другое дело – показанная выше блок-схема: если перед фамилией обнаружится пробел, то чтение слова завершится досрочно. Стало быть, для правильного чтения фамилии надо пропустить стоящие перед нею пробелы (если они есть). Это улучшение слегка усложнит блок-схему (рис. 72).
Рис.72 – Усовершенствованный алгоритм побуквенного чтения фамилии
Достройка программы
В основу новой версии программы «P_31_1» положим программу «P_30_1». Вам следует, прежде всего, открыть её и сохранить под новым именем. Готово? Тогда приступаем к правке.
Начнем с главной программы, где надо изменить имена входных и выходных файлов (чтобы не путать с похожими файлами предыдущей версии).
Assign(InFile,'Journal2.in'); Reset(InFile);
Assign(OutFile,'Journal2.out'); Rewrite(OutFile);
Позаботьтесь о том, чтобы файл «Journal2.in» был похож на настоящий классный журнал с фамилиями, как о нём сказано в начале 30-й главы.
Второе изменение внесем в процедуру обработки строки HandleString. Здесь объявим ещё одну переменную строкового типа, назовем её Fam, она будет вмещать фамилию ученика.
Fam:= ReadFam; { читаем фамилию }
Разумеется, оператор печати строки тоже будет изменен.
Writeln(OutFile, Counter:3, Fam:18, Cnt:8, Sum:14, Rating:11:1);
Осталось выяснить, что такое ReadFam? Это функция чтения фамилии, которую мы напишем по рассмотренному чуть выше алгоритму (рис. 72). Мой вариант функции таков.
function ReadFam: string;
var sym: char; { очередной символ }
S : string; { накопитель строки }
begin
S:=''; { очистка накопителя строки }
{ чтение символов до первой буквы }
repeat Read(InFile, sym); until Ord(sym)>32;
{ чтение последующих символов }
repeat
s:= s+sym;
if Eoln(InFile) then Break;
Read(InFile, sym);
until not ((Ord(sym)>32));
ReadFam:= S; { возвращаемый результат }
end;
Обратите внимание на сравнение введенного символа с пробелом. Это сравнение можно было бы записать так:
sym <> ’ ’
Но пробел в кавычках трудно разглядеть. Лучше сравнивать код символа с кодом пробела (который равен 32), что и сделано внутри функции.
Испытание
Теперь все готово, запустите программу. Что оказалось в выходном файле «Journal2.out»? Наверное, вот это.
Номер Фамилия Количество Сумма Средний
ученика оценок баллов балл
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
Если не считать кривых колонок, неплохо. Кривизну даёт разная длина фамилий учеников. Можно выровнять колонки, вычисляя спецификатор ширины в зависимости от длины фамилии. Или поступить иначе, – дополнить фамилии до одинаковой длины пробелами справа, например:
while Length(Fam) < 12 do Fam:= Fam + Char(32);
Этот оператор уместен после чтения фамилии. Окончательный вариант программы со всеми дополнениями и уточнениями представлен ниже.
{ P_31_1 – Обработка классного журнала, второй этап }
var InFile, OutFile : text; { входной и выходной файлы }
Counter: integer; { счетчик строк в файле }
{----- Функция чтения фамилии -----}
function ReadFam: string;
var sym: char;
S : string;
begin
s:=''; { очистка накопителя строки }
{ чтение символа до первой буквы }
repeat Read(InFile, sym); until Ord(sym)>32;
{ чтение последующих символов }
repeat
s:= s+sym;
if Eoln(InFile) then Break;
Read(InFile, sym);
until not ((Ord(sym)>32));
ReadFam:= S;
end;
{----- Процедура обработки строки -----}
procedure HandleString;
var N : integer; { оценка, прочитанная из файла }
Cnt: integer; { количество оценок }
Sum: integer; { сумма баллов }
Rating: Real; { средний балл }
Fam: string; { фамилия }
begin
Fam:= ReadFam; { читаем фамилию }
{ для выравнивания столбцов добавляем пробелы }
while Length(Fam) < 12 do Fam:= Fam + ' ';
Sum:=0; Cnt:=0; { очищаем накопитель и счетчик оценок }
While not Eoln(InFile) do begin { пока не конец строки }
Read(InFile, N); { читаем оценку в переменную N }
Sum:= Sum+N; { накапливаем сумму баллов }
Cnt:= Cnt+1; { наращиваем счетчик оценок }
end;
if Cnt>0
then begin { если оценки в четверти были }
Rating:= Sum / Cnt; { вычисляем и печатаем ср. балл }
Writeln(OutFile, Counter:3, Fam:18, Cnt:8,
Sum:14, Rating:11:1);
end
else { а если оценок не было }
Writeln(OutFile, Counter:3, Fam:18,' : Ученик не аттестован');
end;
begin {--- Главная программа ---}
Counter:= 0; { обнуляем счетчик строк }
{ открываем входной файл }
Assign(InFile,'Journal2.in'); Reset(InFile);
{ создаем выходной файл }
Assign(OutFile,'Journal2.out'); Rewrite(OutFile);
{ выводим шапку таблицы }
Writeln(OutFile, 'Номер Фамилия Количество Сумма Средний');
Writeln(OutFile, ' оценок баллов балл');
{ пока не конец входного файла… }
while not Eof(InFile) do begin
Counter:= Counter+1; { наращиваем счетчик строк }
HandleString; { обрабатываем строку }
{ переход на следующую строку }
if not Eof(InFile) then Readln(InFile);
end;
{ закрываем оба файла }
Close(InFile); Close(OutFile);
end.
Итоги
• Для чтения отдельного слова в строке файла не годятся ни оператор Readln (он прочитает всю строку), ни оператор Read, который не видит конца строки. Слово читается посимвольно оператором Read с отслеживанием признака окончания строки и других условий.
• Строку выходного файла можно формировать порциями, применяя несколько вызовов процедуры Write. Каждый такой вызов формирует часть строки и продвигает позицию записи, оставляя её в текущей строке. Для перехода к следующей строке вызывается процедура Writeln.
А слабо?
А) Напишите программу для преобразования первого варианта базы данных «Police.txt» (которая содержит по одному числу в строке) во второй вариант (будет содержать по три числа в строке).
Б) Файл с физическими данными старшеклассников содержит три колонки: фамилия, рост и вес ученика. Создайте программы для решения следующих задач:
• отбор кандидатов для занятий баскетболом, – рост кандидата должен составлять не менее 175 см;
• поиск учеников с избыточным весом, для которых разница между ростом ученика (см) и его весом (кг) составляет менее 100.
Ваши программы должны сформировать соответствующие файлы с фамилиями и данными учеников.
- Только для взрослых
- Детям до 16–ти
- Глава 1 Путь далек у нас с тобою…
- Глава 2 Вместо теории
- Глава 3 Консольный интерфейс
- Глава 4 Оружие – к бою!
- Глава 5 Программа номер один
- Глава 6 Подготовка к следующему штурму
- Глава 7 Развиваем успех
- Глава 8 Постоянные и переменные
- Глава 9 Переменные: продолжение знакомства
- Глава 10 Условный оператор
- Глава 11 Операторный блок
- Глава 12 Цикл с проверкой в конце
- Глава 13 Правда и кривда
- Глава 14 Дважды два – четыре
- Глава 15 Айда в Монте-Карло!
- Глава 16 Делу время, а потехе час
- Глава 17 И вновь за парту
- Глава 18 Аз, Буки
- Глава 19 Процедуры и функции: разделяй и властвуй
- Глава 20 Процедуры: первый опыт
- Глава 21 Отладка
- Глава 22 О передаче параметров
- Глава 23 Функции
- Глава 24 Криптография
- Глава 25 Текстовые файлы
- Глава 26 Я не читатель, – я писатель!
- Глава 27 Дайте кораблю минутный отдых!
- Глава 28 Редактор и справочная система
- Глава 29 Читайте по-новому
- Глава 30 Журнальная история
- Глава 31 Финал журнальной истории
- Глава 32 Порядковые типы данных
- Глава 33 Вещественные числа
- Глава 34 Структура программы
- Глава 35 Множества
- Глава 36 Множества в Паскале
- Глава 37 Ввод и вывод множеств
- Глава 38 Множества в «бою»
- Глава 39 Командная игра (массивы)
- Глава 40 Пристрелка на знакомых мишенях
- Глава 41 По порядку, становись!
- Глава 42 Кто ищет, тот всегда найдет
- Глава 43 Сортировка по-взрослому
- Глава 44 Строки
- Глава 45 Очереди и стеки
- Глава 46 Огромные числа
- Глава 47 Системы счисления
- Глава 48 Железная логика
- Глава 49 Сложные массивы
- Глава 50 Неспортивные рекорды (записи)
- Глава 51 Указатели в море памяти
- Глава 52 Динамические переменные
- Глава 53 Массив указателей
- Глава 54 Односвязные списки
- Глава 55 Слова, слова, слова…
- Глава 56 И снова очереди, и снова стеки…
- Глава 57 Графомания
- Глава 58 По графу шагом марш!
- Глава 59 Крупные проекты
- Глава 60 Мелкие хитрости
- Глава 61 «Кубики» программиста (ООП)
- Глава 62 Самое интересное только начинается!
- Приложение А Установка и настройка IDE Borland Pascal
- Приложение Б Консольная программа в среде Delphi
- Приложение В Особенности IDE Pascal ABCNet
- Приложение Г Зарезервированные слова
- Приложение Д Ошибки компиляции
- Приложение Е Ошибки исполнения
- Приложение Ж Директивы управления компиляцией
- Приложение З Назначение пунктов меню
- Приложение И Стандартная кодировка символов MS–DOS
- Приложение К Некоторые встроенные процедуры и функции
- Приложение Л Перечень программ
- Приложение М Пример олимпиадной задачи
- Библиография
- Содержание книги
- Популярные страницы
- Из истории вычислительной техники
- Из истории персональных компьютеров
- Глава десятая. Из истории файловых систем
- Глава 76 Создайте уникальное торговое предложение (УТП) на основе своей истории
- 36. Истории потребителей и самореализованный покупатель
- Часть 4 Российский бизнес: истории развития
- Глава 10. Истории готовят как торты
- Блок № 3. Истории
- Глава 7. Как нужно рассказывать истории
- Глава 17. Истории – это нечто вроде астероидов
- Учимся рассказывать истории
- Социальные действия и социальные истории