SHPORA.net :: PDA

Login:
регистрация

Main
FAQ

гуманитарные науки
естественные науки
математические науки
технические науки
Search:
Title: | Body:

Модули и текстовые файлы


Модули в Turbo Pascal



В Turbo Pascal каждый модуль представляет собой отдельный файл (один файл!), который имеет расширение .pas.



Исходный текст модуля имеет следующую структуру:

1. Заголовок

2. Интерфейсная часть

3. Исполнительная часть

4. Секция инициализации



Заголовок

Заголовок модуля состоит из ключевого слова UNIT и идентификатора – имени модуля. Модуль должен быть сохранен в файле, имя которого совпадает с именем модуля. Например, если модуль начинается со строки

Unit MyUnit;

тогда этот модуль должен быть сохранен в файле с именем MyUnit.pas



Интерфейсная часть

Дадим краткое определение:

интерфейс – это способ взаимодействия.

В данном случае интерфейс – способ взаимодействие основной программы (или другого модуля) с нашим модулем. Взаимодействие с модулем производится через использование определенных в модуле констант, типов, глобальных переменных (чего делать не надо!!!), и через вызов определенных в модуле процедур и функций.

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

Интерфейсная часть модуля начинается с ключевого слова interface и заканчивается перед ключевым словом implementation. Интерфейсная часть модуля содержит почти те же разделы что и основная программа:

- раздел объявления используемых модулей

- раздел объявления констант

- раздел объявления типов

- раздел объявления переменных

- раздел объявления процедур и функций

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

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



Исполнительная часть

Если в интерфейсной части указываются только заголовки подпрограмм, (подпрограммы объявляются), то в исполнительную часть модуля включаются тела подпрограмм, (подпрограммы определяются). Исполнительная часть модуля начинается с ключевого слова implementation и заканчивается началом секции инициализации, если она есть, либо словом end с точкой. Исполнительная часть модуля содержит те же разделы что и основная программа:

- раздел объявления используемых модулей

- раздел объявления констант

- раздел объявления типов

- раздел объявления переменных

- раздел определения процедур и функций

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

Все что объявлено в исполнительной части может быть использовано только внутри исполнительной части (!!! Обратите на это внимание !!!). С другой стороны в исполнительной части может быть использовано все, что объявлено в интерфейсной части.



Секция инициализации



Иногда перед использованием подпрограмм, включенных в модуль, требуется произвести инициализацию некоторых глобальных переменных этого модуля. Необходимые действия можно произвести в секции инициализации модуля. Операторы этой секции выполняются единственный раз в момент запуска программы. Секция инициализации размещается в самом конце модуля, начинается она словом begin, заканчивается end (с точкой). Если инициализация в модуле не требуется, то в секции помещается только end (с точкой).





Пользовательские модули для работы с текстом



Рассмотрим использование модулей в задачах обработки текстов.

Разработаем модуль, в котором соберем функции и процедуры, используемые в двух задачах:

Задача 1.

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

Ограничение: считаем, что строки в файле не превышают нормальной длины в 70-80 символов.



Задача 2.

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

Переписать содержимое исходного файла в выходной файл, выделяя БОЛЬШИМИ буквами все выделенные при выводе на экран слова.

Примечание: Имя входного файла вводится с клавиатуры. Имя выходного файла отличается от имени исходного файла только расширением.



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



Вот этот модуль:



{Модуль Words.

Содержит функции поиска и анализа слов в строке.

}

unit Words;





interface {интерфейсная часть модуля}



{Функция FindNextWord.

Ищет в строке S следующее слово начиная с символа Start.

Если слово найдено, то возвращается True,

и возвращается индекс первого символа слова (через BeginWord)

и его длина (через LengthWord).

Если слово не найдено, возвращается False.}

function FindNextWord( const S : String;

Start : Integer;

var BeginWord : Byte;

var LengthWord : Byte) : Boolean;



{Функция FindMaxLenWord.

Ищет в строке S самое длинное слово.

Если ни одного слова в строке S не найдено, то возвращается False.

В противном случае возвращается True,

при этом через BeginMaxWord возвращается индекс

первого символа самого длинного слова,

а через LengthMaxWord - его длина.}

function FindMaxLenWord( const S : String;

var BeginMaxWord : Byte;

var LengthMaxWord : Byte

) : Boolean;







{Функция IsChereda.

Возвращает True, если S содержит строку, состоящую только

из чередующихся русских согласных и русских гласных букв.

Возвращает False в противном случае. }

function IsChereda(const S:string):Boolean;





implementation {Исполнительная часть модуля}



const

{множества символов}

SmallRusLetters : set of char = ['а'..'п','р'..'я','ё'];

BigRusLetters : set of char = ['А'..'Я','Ё'];



SmallLatLetters : set of char = ['a'..'z'];

BigLatLetters : set of char = ['A'..'Z'];



Digits : set of char = ['0'..'9'];



RusGlasn : set of char = ['а','е','ё','и','о',

'у','ы','э','ю','я',

'А','Е','Ё','И','О',

'У','Ы','Э','Ю','Я'];

var

RusLetters : set of char; {все русские буквы}

LatLetters : set of char; {все латинские буквы}

Letters : set of char; {все буквы и цифры,

т.е. те символы, из которых

могут состоять слова}

RusSoglasn : set of char; {русские согласные буквы}







{=====================================================}

{Функция IsLetter.

Возвращает True, если C является символом слова.

Возвращает False, если C является разделителем. }

function isLetter(c: char): boolean;

begin

isLetter:=c in Letters;

end;



{=====================================================}

{Функция IsRusGlasn.

Возвращает True, если C является русской гласной буквой.

Возвращает False в противном случае. }

function isRusGlasn(c: char): boolean;

begin

isRusGlasn := c in RusGlasn;

end;



{=====================================================}

{Функция IsRusSoglasn.

Возвращает True, если C является русской согласной буквой.

Возвращает False в противном случае. }

function isRusSoglasn(c: char): boolean;

begin

isRusSoglasn := c in RusSoglasn;

end;



{=====================================================}

{Функция IsChereda.

Возвращает True, если S содержит строку, состоящую только

из чередующихся русских согласных и русских гласных букв.

Возвращает False в противном случае. }

function IsChereda(const S:string):Boolean;

var

IsSogl : Boolean; {текущая буква является согласной}

IsPrevSogl : Boolean; {предыдущая буква является согласной}

i : Byte; {счетчик цикла}

len : Byte; {длина строки}

begin

len := length(S); {вычисляем длину строки}

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

и согласных букв}

for i := 1 to len do

if not IsRusGlasn(s[i]) and not IsRusSoglasn(s[i]) then

begin

{если нет, то завершаем работу функции}

IsChereda := false;

exit;

end;



{начиная со второго символа слова, и до конца слова}

for i := 2 to len do

{ЭТОТ символ должен быть НЕ ТАКИМ как ПРЕДЫДУЩИЙ}

if IsRusSoglasn(s[i-1]) <> IsRusGlasn(s[i]) then

begin

{если нет, то завершаем работу функции}

IsChereda := false;

exit;

end;

IsChereda := true; {все символы чередуются}

end;





{=====================================================}

{Функция FindNextWord.

Ищет в строке S следующее слово начиная с символа Start.

Если слово найдено, то возвращается True,

и возвращается индекс первого символа слова (через BeginWord)

и его длина (через LengthWord).

Если слово не найдено, возвращается False.}

function FindNextWord( const S : String;

Start : Integer;

var BeginWord : Byte;

var LengthWord : Byte) : Boolean;

var

i : Integer; {индекс может выйти за границы 255 - поэтому Byte

использовать нельзя!!!}

Len : Byte; {длина строки}

Begin

{вычисляем длину строки}

Len := length(s);

{ищем начало слова, начиная со стартового символа строки}

i := Start;

{в цикле продвигаем i вперед по строке, до тех пор

пока не встретиться буква, или пока не кончится строка }

while not isLetter(S[i]) and (i <= Len ) do

i := i + 1;

{сейчас i указывает на первый символ найденного слова}

BeginWord := i;

{ищем конец слова}

{для этого продвигаем i вперед, до тех пор пока не встретиться

НЕ БУКВА, или пока i не выйдет за пределы строки}

while isLetter(S[i]) and ( i <= Len ) do

i := i + 1;



{сейчас i указывает на первый символ-разделитель, следующий

за словом (или i указывает на символ за пределами границ

строки).

Длину слова вычисляем как разность между индексами его

последнего и первого символов }

LengthWord := i - BeginWord;



{Если вычисленная длина слова больше 0, значит слово в строке

найдено - возвращаем True.

Иначе - слова в строке нет - возвращаем False }

if LengthWord > 0

then FindNextWord := true

else FindNextWord := false;

end;





{=====================================================}

{Функция FindMaxLenWord.

Ищет в строке S самое длинное слово.

Если ни одного слова в строке S не найдено, то возвращается False.

В противном случае возвращается True,

при этом через BeginMaxWord возвращается индекс

первого символа самого длинного слова,

а через LengthMaxWord - его длина.}

function FindMaxLenWord( const S : String;

var BeginMaxWord : Byte;

var LengthMaxWord : Byte

) : Boolean;

var

i : Integer; {индекс может выйти за границы 255 - поэтому Byte

использовать нельзя!!!}

Beg : Byte; {начало строки}

Len : Byte; {длина строки}

begin

I := 1; {начинаем поиск слов с начала строки}

LengthMaxWord := 0; {длина самого длинного слова в строке =0,

потому что еще не одного слова не нашли }

{ищем все слова в строке}

while FindNextWord(S,i,Beg,Len) do

begin

{Если найденное слово длиннее всех ранее найденных}

if len>lengthMaxWord then

begin {запоминаем начало и длину найденного слова}

lengthMaxWord:=len;

BeginMaxWord:=beg;

end;

i:=beg+len; {продолжаем поиск с символа, следующего за

концом последнего найденного слова}

end;



{если не одного слова в строке не найдено,

то длина самого длинного слова будет равна 0.

В этом случае возвращаем False.

В противном случае возвращаем True.}

if lengthMaxWord=0

then findMaxLenWord:=False

else findMaxLenWord:=True;

end;







begin {Секция инициализации}

{"собираем" множества из подмножеств }

RusLetters := smallRusLetters + bigRusLetters;

LatLetters := smallLatLetters + bigLatLetters;

Letters := RusLetters + LatLetters + Digits;

RusSoglasn := RusLetters - RusGlasn;

end.











Теперь приведем текст программы – решение первой задачи:



{

Задача 1.

Переписать входной файл в выходной файл.

При этом самое длинное слово в каждой строке

выделить угловыми скобками.

Ограничение: считаем, что строки в файле не превышают

нормальной длины в 70-80 символов.

}

uses Words; {В программе используется функция findMaxLenWord}



var

inFileName : string; {имя входного файла}

outFileName : string; {имя выходного файла}

inFile : text; {входной файл}

outFile : text; {выходной файл}



S : string; {строка, читаемая из файла}

beg : Byte; {начало самого длинного слова}

len : Byte; {длина самого длинного слова}



begin

{Ввод имен входного и выходного файлов}

write('Введите имя входного текстового файла : ');

readln(inFileName);



write('Введите имя выходного текстового файла : ');

readln(outFileName);



{Открытие входного файла на чтение}

assign(inFile, inFileName);

reset(inFile);



{Открытие выходного файла на запись}

assign(outFile, outFileName);

rewrite(outFile);



{пока не кончится входной файл}

while not eof(inFile) do

begin

{читаем из входного файла строку}

readln(inFile, s);

{если в строке найдено хоть одно слово}

if findMaxLenWord(s, beg, len) then

begin

{самое длинное слово выделяем угловыми скобками}

Insert('<',S,beg);

Insert('>',S,beg+len+1);

end;

{выводим в выходной файл измененную строку S}

writeln(outFile, s);

end;



{Закрываем входной и выходной файлы}

close(inFile);

close(outFile);

end.





Как мы видим, в этой программе используется наш модуль Words. За счет этого текст программы достаточно краток.



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



{Модуль Chars.

Содержит функции конверсии символов и строк.}

unit chars;





interface





{превратить маленькие буквы в большие}

function ToUpper(ch: char): char;



{превратить большие буквы в маленькие}

function ToLower(ch: char): char;



{превратить маленькие буквы в большие для строки S}

function StringToUpper(const S: string): string;





implementation





{превратить маленькие буквы в большие}

function ToUpper(ch:char):char;

begin

{Для понимания алгоритма загляни в таблицу ASCII кодов}

{Общая схема такая :

ord(ch)-ord('x') - вычисление "расстояния"

до опорного символа

+ ord('X') - вычисленное расстояние прибавляется

к новому опорному символу

chr(...) - превращения порядкового номера символа в символ

}

if ch in ['а'..'п'] then

ToUpper := chr(ord(ch) - ord('а') + ord('А'))

else if ch in ['р'..'я'] then

ToUpper := chr(ord(ch) - ord('р') + ord('Р'))

else if ch = 'ё' then

ToUpper := 'Ё'

else if ch in ['a'..'z'] then

ToUpper := chr(ord(ch) - ord('a') + ord('A'))

else

ToUpper := ch;

end;



{превратить большие буквы в маленькие}

function ToLower(ch:char):char;

begin

if ch in ['А'..'П'] then

ToLower := chr(ord(ch) - ord('А') + ord('а'))

else if ch in ['Р'..'Я'] then

ToLower := chr(ord(ch) - ord('Р') + ord('р'))

else if ch = 'Ё' then

ToLower := 'ё'

else if ch in ['A'..'Z'] then

ToLower := chr(ord(ch) - ord('A') + ord('a'))

else

ToLower := ch;

end;



{превратить маленькие буквы в большие для строки S}

function StringToUpper(const S:string):string;

var

i : Byte;

resString: string;

begin

{результат заносится в строку resString}

resString:='';

{по очереди все символы исходной строки S превращаются

в большие}

for i := 1 to length(s) do

resString := resString + ToUpper(s[i]);

{получившаяся строка возвращается}

StringToUpper := resString;

end;



begin

end.



И наконец, текст программы – решение второй задачи:







{

Задача 2.

Дан исходный файл с текстом на русском языке.

Вывести на экран содержимое исходного файла постранично.

При выводе на экран выделить цветом все слова, в которых

чередуются гласные/согласные.

Переписать содержимое исходного файла в выходной файл,

выделяя БОЛЬШИМИ буквами все выделенные при выводе на экран

слова.



Примечание: Имя входного файла вводится с клавиатуры. Имя

выходного файла отличается от имени исходного файла только

расширением.

}

uses Words, {В программе используется функция FindNextWord

и IsChereda}

Chars, {используется StringToUpper}

Crt; {используется ReadKey и др.}







{Процедура PrintFile.

Вывод содержимого файла FileName на экран постранично.

Одна страница - 20 строк.

При выводе на экран выделяются цветом все слова, в которых

чередуются гласные/согласные.}

procedure PrintFile(const FileName:string);

var

InFile : text; {входной файл}

S : string; {строка, читаемая из файла}

NumLines : LongInt; {номер строки, читаемой из файла}

NumPages : LongInt; {номер страницы, выводимой на экран}

i : Integer; {счетчик}

beg, len : byte; {начало и длина слова}

w : string; {слово}

begin

{Открытие входного файла на чтение}

assign(inFile, FileName);

reset(inFile);

{Инициализация количества прочитанных строк

и выведенных страниц}

NumLines := 0;

NumPages := 0;



{пока не кончится входной файл}

while not eof(inFile) do

begin

readln(inFile, s); {читаем из входного файла строку}

inc(NumLines); {увеличиваем номер прочитанной строки}

write(NumLines:3,'> '); {выводим номер строки на экран}

{ищем по очереди все слова}

i:=1;

while FindNextWord(s,i,beg,len) do

begin

{серым цветом выводим все разделители

перед очередным словом}

textcolor(lightgray);

write( copy(s, i, beg-i) );

{в W заносим найденное слово}

w:=copy(s,beg,len);

{если в слове W чередуются гласные и согласные}

{тогда устанавливаем ДРУГОЙ цвет вывода}

if IsChereda(w) then textcolor(yellow);

{выводим слово}

write(w);

{продолжать поиск слов...}

i:=beg+len;

end;

{разделители за последим словом выводим серым цветом}

textcolor(lightgray);

writeln(copy(s,i,length(s)-i+1));



{Если очередные 20 строк выведены - страница}

if NumLines mod 20 = 0 then

begin

{увеличиваем номер страницы}

inc(NumPages);

{выводим номер страницы }

write('======================= ');

write('Страница ', NumPages:4);

write(' =======================');

{выводим пустые строки}

writeln;

writeln;

writeln;

writeln;

{ждем нажатия какой-нибудь клавиши}

ReadKey;

end;

end;



{после последней страницы выводим сообщение

об окончании вывода}

inc(NumPages);

write('=======================');

write('Страница ', NumPages:4);

writeln('=======================');

writeln('Весь текст выведен!');

ReadKey;



{Закрываем входной файл}

close(inFile);

end;









{

Функция CreateOutFileName.

Создает и возвращает имя выходного файла путем

замены расширения в имени входного файла InFileName.}

function CreateOutFileName( const InFileName : string

) : string;

var

OutFileName: string; {имя выходного файла}

PosPoint: Byte; {позиция точки в имени входного файла}

begin

{ищем точку в имени входного файла}

PosPoint := Pos('.', InFileName);

if PosPoint = 0 then {точки в имени нет}

OutFileName := InFileName + '.'

else {точка в имени файла есть}

OutFileName := Copy(InFileName, 1, PosPoint);

{считаем, что входной файл имеет расширение отличное от OUT!!!}

OutFileName := OutFileName + 'out';

CreateOutFileName := OutFileName;

end;





{Процедура CopyText.

Копирует содержимое исходного файла InFileName

в выходной файл, выделяя БОЛЬШИМИ буквами все слова,

в которых чередуются гласные/согласные.}

procedure CopyText(const InFileName: string);

var

InFile : text; {входной файл}

OutFileName : string; {имя выходного файла}

OutFile : Text; {выходной файл}

S : string; {строка, читаемая из файла}

i : Integer; {счетчик}

beg, len : byte; {начало и длина слова}

w : string; {слово}



begin

{создаем имя выходного файла на основании имени входного}

OutFileName := CreateOutFileName(InFileName);



{Открытие входного файла на чтение}

assign(inFile, InFileName);

reset(inFile);



{Открытие выходного файла на запись}

assign(outFile, OutFileName);

rewrite(outFile);



{пока не кончится входной файл}

while not eof(inFile) do

begin

readln(inFile, s); {читаем из входного файла строку}

{ищем в строке по очереди все слова}

i:=1;

while FindNextWord(s,i,beg,len) do

begin

{выводим все разделители перед очередным словом}

write(outFile, copy(s,i,beg-i));

{в W заносим найденное слово}

w:=copy(s,beg,len);

{если в слове W чередуются гласные и согласные}

{тогда делаем все буквы этого слова большими}

if IsChereda(w) then W:=StringToUpper(W);

{выводим слово}

write(outFile, w);

{продолжать поиск слов...}

i:=beg+len;

end;

{выводим разделители за последним словом}

writeln(outFile, copy(s,i,length(s)-i+1));

end;



{закрытие файлов}

close(inFile);

close(outFile);

end;







var

inFileName : string; {имя входного файла}

begin

{Ввод имени входного файла}

write('Введите имя входного текстового файла : ');

readln(inFileName);

{Печатаем входной файл (на экране, постранично)}

PrintFile(inFileName);

{Копируем входной файл в выходной}

CopyText(InFileName);

end.









ЗАМЕЧАНИЯ:

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

1. Пользователь модуля имеет полную информацию об использовании подпрограмм модуля. И при этом он не имеет никакой информации о способе реализации подпрограмм.

2. Модули должны быть, как можно меньше зависимы друг от друга (в идеале модули должны быть полностью независимы друг от друга)



Первый принцип реализуется за счет:

- разбиения констант, типов, переменных и подпрограмм модуля на те, которые необходимо открыть пользователям (их надо разместить в интерфейсной части), и на те, которые должны быть закрыты от пользователя (их надо разместить в исполнительной части);

- наиподробнейшего комментирования интерфейсной части модуля

- использование смысловых имен для констант, типов, переменных и подпрограмм.

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