Введение
В соответствии с поставленной задачей необходимо разработать программу, которая будет считывать текст из файла, затем проводить его анализ на предмет вхождения заданной подстроки с учетом заданных параметров (h % символов может не совпадать, различие прописных символов). Далее найденная подстрока заменяется на заданную, но по желанию пользователя можно вернуть текст в первоначальное состояние
Задание.
В текстовом файле требуется найти все вхождения заданной подстроки с учетом того, что не более h % символов может не совпадать. Необходимо предусмотреть два режима работы: с различением строчных и прописных букв и без различения. Найденные подстроки должны заменяться на другую подстроку, указанную пользователем, а также сохраняться в виде связанной динамической структуры данных. Необходимо предусмотреть откат изменений исходного текста по сохраненной информации.
Постановка задачи
Описание ограничений, накладываемых на исходные данные.
В соответствии с условием задачи исходные данные представляют собой текстовый файл. Для правильного выполнения поставленной задачи должны выполняться следующие условия:
- текст в файле должен быть записан с помощью кириллической кодировки (MS-DOS);
- обрабатываемый текст должен быть написан в соответствии с правилами русского языка;
- коэффициент совпадения символов должен быть в пределах от 0 до 1;
- искомая строка и строка замены должны представлять собой слова;
Формы представления результатов работы программы.
Результатом правильной работы программы является текстовый файл, в котором подстроки удовлетворяющие параметрам поиска заменены на заданную подстроку. В случае несоответствия обрабатываемого текста накладываемым ограничениям, текст в файле останется без изменений.
Разработка алгоритмов
Работу программы можно условно представить в виде следующей последовательности действий:
1. получение адреса файла;
2. поиск слов соответствующих заданным условиям (подстрока для поиска, процент совпадения, различать или нет строчные и прописные буквы);
3. замена найденных слов на заданное и вывод текста;
4. сохранение или не сохранение изменений.
Действия 2 –3 целесообразно реализовать в виде отдельных подпрограмм.
Процедура поиска подстроки, должна возвращать данные о всех подстроках, удовлетворяющих условиям, т.е. саму подстроку и ее позицию в файле.
Процедура замены найденных подстрок должна оставлять без изменений весь текст программы, за исключением подстрок, находящихся на определенных позициях (эти подстроки и их позиции передаются из процедуры поиска чисел), и в итоге вывести измененный текст.
Процедура отката текста по сохраненной информации должна вернуть текст в первоначальное состояние по принципу процедуры замены найденных подстрок
Подпрограмма поиска вхождений заданной подстроки.
Подпрограмма посимвольно считывает файл, анализирует и подсчитывает считанные символы. Сначала задается такой параметр поиска, как различать или нет строчные и прописные символы. После этого происходит считывание и анализ символов, составляющих следующее слово. Если оно соответствует заданным параметрам, то запоминается слово и его позиция относительно предыдущего по исходному тексту слова.
Т.к. заранее неизвестно количество включений в обрабатываемый текст чисел, обозначающих денежные наименования, то для сохранения данных целесообразно использовать связанный список. Элементы списка должны содержать следующие поля:
само слово (строковая переменная), смещение относительно предыдущего включения (целочисленная переменная).
Подпрограмма, заменяющая в файле подстроки удовлетворяющие условиям поиска на заданную
Т.к. напрямую вставить слово в файл вместо другого слова невозможно, то необходимо выполнить следующую последовательность действий.
Сформировать вспомогательный файл. Скопировать все содержимое обрабатываемого файла во вспомогательный, стереть содержимое обрабатываемого файла. Затем скопировать из вспомогательного файла символы до первой заменяемой подстроки (количество символов (т.е. позицию подстроки в тексте) получим из подпрограммы поиска, описанной выше). После этого найденная подстрока заменяется на подстроку замены и вставляется в конец обрабатываемого файла. Во вспомогательном файле указатель смещается на количество символов исходной подстроки и снова повторяется эта последовательность действий. Далее происходит копирование оставшихся символов из вспомогательного файла в исходный и уничтожение вспомогательного файла.
В конце происходит посимвольный вывод получившегося файла
Подпрограмма, осуществляющая откат изменений исходного текста по сохраненной информации.
Т.к. напрямую вставить слово в файл вместо другого слова невозможно, то необходимо выполнить следующую последовательность действий.
Сформировать вспомогательный файл. Скопировать все содержимое обрабатываемого файла во вспомогательный, стереть содержимое обрабатываемого файла. Затем скопировать из вспомогательного файла символы до первой заменяемой подстроки (количество символов (т.е. позицию подстроки в тексте) и саму подстроку получим из подпрограммы поиска, описанной выше). После этого найденная подстрока заменяется на исходную подстроку и вставляется в конец обрабатываемого файла. Во вспомогательном файле указатель смещается на количество символов исходной подстроки и снова повторяется эта последовательность действий. Далее происходит копирование оставшихся символов из вспомогательного файла в исходный и уничтожение вспомогательного файла.
Вспомогательные подпрограммы.
Так как в программе используется динамический список, то удобно создать отдельную подпрограмму освобождения памяти, выделенной под динамический список.
Эта подпрограмма реализуется в виде цикла с предусловием, условием выхода из которого будет наличие пустого указателя, на который ссылается первый элемент списка. В теле цикла выполняются три действия: присваивание значения указателя на первый элемент вспомогательному указателю, присваивание указателю на первый элемент адреса второго элемента, удаление элемента, хранящегося по адресу вспомогательного элемента.
После выхода из цикла происходит освобождение памяти по адресу первого элемента.
В ходе выполнения этой подпрограммы может возникнут ситуация, когда на первой итерации цикла указатель на первый элемент будет пустым (т.е. в подпрограмму передастся пустой список). Тогда окажется невозможным обращение ко второму элементу списка и компилятор выдаст ошибку. Во избежание этой ситуации есть смысл добавить в начало подпрограммы дополнительное условие проверки указателя на первый элемент.
Разработка программы.
Основная часть программы.
Для реализации разработанного выше алгоритма будет использован язык программирования высокого уровня Паскаль.
В основной части программы от пользователя будет запрашиваться путь к файлу, сохраняться он будет в виде строковой переменной. С помощью процедуры Assign(var f:file; name of file:string) с этой строковой переменной файловую переменную f.
Также будут запрашиваться строка для поиска (переменная типа string), подстрока для замены (также типа string) и процент совпадения h(переменная типа real).
Затем будет вызываться подпрограмма поиска заданной подстроки. Ее целесообразно реализовать в виде функции, возвращаемым значением будет указатель на первый элемент связанного списка. В функцию будет передаваться файловая переменная.
Функция будет называться poisk и иметь прототип poisk(var f:text;s2:string;h:real):ptrt. Программа вызовет функцию poisk, в качестве аргумента передаст файловую переменную f, текстовую переменную s2 и переменную типа real h, а в качестве возвращаемого значения будет использован указатель pfirst.
Используя условный оператор if программа проверит, является ли указатель pfirst пустым. Если нет, то вызовет подпрограмму, заменяющую в файле найденные подстроки соотетствующие критериям поиска на заданную подстроку. Т.к. никакого значения она не возвращает, то реализовать ее надо в виде процедуры. Называться она будет output. Ее прототип output(var f:text; pfirst:ptrt; s3:string). В качестве аргументов ей будет передаваться файловая переменная f , указатель на первый элемент связанного списка pfirst и подстрока замены s3 типа real.
Используя условный оператор if программа проверит, является ли указатель pfirst пустым. Если нет, то будет выполнен запрс на откат по сохраненной информации, и если его необходимо выполнить, то вызовет подпрограмму, заменяющую в файле новые подстроки на заданные подстроки. Т.к. никакого значения она не возвращает, то реализовать ее надо в виде процедуры. Называться она будет vstavka. Ее прототип vstavka (var f:text; pfirst:ptrt; s3:string). В качестве аргументов ей будет передаваться файловая переменная f , указатель на первый элемент связанного списка pfirst и подстрока замены s3 типа real.
После ее выполнения, в случае не пустоты списка будет вызвана процедура удаления списка – liberate(first:ptrt). Ей в качестве аргумента передается указатель на первый элемент – pfirst.
После этого заканчивается выполнение программы.
Функция poisk(var f:text; s2:string;h:real):ptrt.
В начале происходит открытие файла, связанного с переменной f. Для этого используется процедура reset(var f:file). Для проверки успешности выполнения этой процедуры используется функция IOResult:integer. Если она имеет ненулевое значение, то выводится сообщение об ошибке, а выполнение функции прекращается.
Затем используется цикл с предусловием while. В качестве условия цикла будет использована функция eof(var f:file):boolean, в качестве аргумента которой будет использована переменная f. Для правильного функционирования нужно инвертировать условие с помощью оператора not.
Далее в теле цикла происходит посимвольное считывание в cсимвольную переменную c из файла, c помощью процедуры read. С помощью переменной n происходит подсчет считанных символов.
Если, считанный символ является символом русского или английского алфавита, то запускается цикл while, работающий до тех пор, пока не будет достигнут пробел, или конец файла. В теле цикла происходит объединение всех считанных символов в строку s1 с помощью функции concat(s1, [s2..sN]:string):string, считывается следующий символ в файле, а также инкрементируется переменная n.
Далее происходит сравнение найденного слова с эталоном (подстрокой для поиска): подсчитывается количество соответственно совпавших символов. При этом пользователь должен выбрать различать или не различать строчные и прописные буквы, и если необходимо не различать, то при сравнении символов применяется процедура Upcase, которая в случае что буква строчная, возвращает ее прописное значение. Формат процедуры Upcase(c), где с – переменная символьного типа.
После этого проверяется процент совпадения элементов: если отношение количества совпавших символов к количеству символов наименьшего из сравниваемых слов больше либо равно h, то к счетчику вхождений прибавляется единица и также происходит выделение памяти под элемент динамического списка и запись в него s1 (обрабатываемое слово), результата выражения (n-2-length(s2)-length(s1)) (смещение от предыдущего слова).
В конце функции присваивается значение указателя на первый элемент списка pfirst или nil, в случае, если ни одного включения необходимого сочетания в файле нет.
Процедура output(var f:text; pfirst:ptrt; s3: string)
Процедура формирует вспомогательный файл, c которым она связывает файловую переменную f1, затем открывает его на запись с помощью процедуры rewrite(var f:file), а также открывает на чтение файл, c которым связана переменная f, передающаяся в процедуру как аргумент.
Для контроля успешности открытия файлов используется функция IOResult.
Если при открытии файла произошли ошибки, то процедура выдаст сообщение об ошибке и прекратит свое выполнение, в ином случае, с помощью цикла с постусловием repeat все содержимое файла f в файл f1. Это происходит в теле цикла с помощью посимвольного считьывания содержимого файла f в символьную c и последующей посимвольной записи с в файл f1. Условием выхода из цикла является конец файла f (об этом сигнализирует функция eof).
После этого оба файла закрываются процедурой close(var f:file).
Файл f1 открывается на чтение (reset), а файл f - очищается и открывается для записи (rewrite).
Запускается цикл while, условием выполнения которого является неравенство указателя phelp нулю. (phelp – указатель на текущий элемент списка, на первой итерации он равен pfirst). Внутри этого цикла запускается итерационный цикл, количество повторений которого равно количеству символов перед перед обрабатываемым словом. Оно хранится в динамическом списке. В теле цикла происходит копирование символа из f1 в f..
Далее подстрока замены s3 записывается в f. С помощью итерационного цикла указатель в файле f1 смещается на количество символов, равное количеству символов исходного слова. Происходит переход к следующему элементу динамического связанного списка.
После окончания этого цикла, необходимо запустить цикл while, который будет работать до конца файла f1. В его теле будет происходить посимвольное «дописывание» в f тех символов f1, которые находятся после последнего найденного слова.
После этого происходит закрытие обоих файлов (close). И уничтожение файла, связанного с переменной f1 (erase(var f:file)).
Последним является открытие файла f, его посимвольное считывание и посимвольный вывод на экран.
Процедура vstavka(var f:text; pfirst:ptrt)
Процедура формирует вспомогательный файл, c которым онна связывает файловую переменную f1, затем открывает его на запись с помощью процедуры rewrite(var f:file), а также открывает на чтение файл, c которым связана переменная f, передающаяся в процедуру как аргумент.
Для контроля успешности открытия файлов используется функция IOResult.
Если при открытии файла произошли ошибки, то процедура выдаст сообщение об ошибке и прекратит свое выполнение, в ином случае, с помощью цикла с постусловием repeat все содержимое файла f в файл f1. Это происходит в теле цикла с помощью посимвольного считьывания содержимого файла f в символьную c и последующей посимвольной записи с в файл f1. Условием выхода из цикла является конец файла f (об этом сигнализирует функция eof).
После этого оба файла закрываются процедурой close(var f:file).
Файл f1 открывается на чтение (reset), а файл f - очищается и открывается для записи (rewrite).
Запускается цикл while, условием выполнения которого является неравенство указателя phelp нулю. (phelp – указатель на текущий элемент списка, на первой итерации он равен pfirst). Внутри этого цикла запускается итерационный цикл, количество повторений которого равно количеству символов перед перед обрабатываемым словом. Оно хранится в динамическом списке. В теле цикла происходит копирование символа из f1 в f..
Далее исходное слово, хранящееся в динамической структуре записывается в f. С помощью итерационного цикла указатель в файле f1 смещается на количество символов, равное количеству символов подстроки замены. Происходит переход к следующему элементу динамического связанного списка.
После окончания этого цикла, необходимо запустить цикл while, который будет работать до конца файла f1. В его теле будет происходить посимвольное «дописывание» в f тех символов f1, которые находятся после последнего обрабатываемого слова.
После этого происходит закрытие обоих файлов (close). И уничтожение файла, связанного с переменной f1 (erase(var f:file)).
Процедура liberate(first:ptrt)
Т.к. программа использует динамический список, то встает необходимость освобождения памяти в конце выполнения программы. Для этого используется функция liberate.
Ее аргументом является указатель на первый элемент списка. Если список не пуст, то используя цикл while выполняется следующая последовательность действий: вспомогательному указателю help присваивается адрес первого элемента списка, указателю first присваивается адрес второго элемента, элемент, на который ссылается help, уничтожается с помощью процедуры dispose(var p). Цикл работает до тех пор, пока второй элемент существует. После его выполнения происходит уничтожение первого элемента.
Структура данных.
Программа считывает данные из текстового файла. Внутри программы данные передаются в виде связанного списка. Каждый элемент списка является записью следующего вида:
kos=Record
Pod:string; {подстрока, которое заменяется программой}
Sm:longint;{смещение относительно предыдущего обработанного слова)
Next:ptrt; {указатель на следующий элемент списка}
End;
На выходе программа выдает текстовый файл с измненными найденными подстроками.
Руководство оператора.
Назначение программы.
Программа предназначена для работы с текстовым файлом. Если в тексте, содержащимся в файле находится хотя бы одно вхождение заданной подстроки, то она будет заменена на подстроку замены по желанию пользователя.
Условия выполнения программы.
Для корректной работы программы достаточно:
-процессор с тактовой частотой 100 мГц;
-оперативная память 4 мБ;
-память на жестком диске 16 мБ;
-оперативная система MS-DOS;
Выполнение программы.
Для запуска программы необходимо запустить файл kursovoi.exe.
В ходе выполнения программы последовательно выводятся сообщения:
1. «Введите путь к файлу» - пользователь должен ввести путь к обрабатываемому текстовому файлу;
2. «Введите подстроку для поиска», после которого пользователь должен ввести подстроку для поиска (эталон);
3. «Введите подстроку для замены», после которого пользователь должен ввести подстроку, которой он хочет изменить искомую подстроку.
4. «Введи коэффициент совпадения» - пользователь должен ввести процент совпадения символов найденной подстроки и эталона.
5. «Введите 1, если хотите различать строчные и прописные буквы, и 0, если не хотите» - пользователь выбирает: различать строчные и прописные буквы (вводит “1” ) , или не различать (вводит “0” ).
6. «Введите 1, если хотите выполнить замену, и 0, если не хотите» - пользователь выбирает сохранить изменения текста (вводит “1” ) , или не сохранять (вводит “0” ).
Программа в ходе выполнения преобразует текстовый файл. Результатом правильного выполнения программы является текстовый файл, измененный в соответствии с указаниями пользователя.
Сообщение оператору.
«Ошибка открытия файла» – файл, находящийся по адресу, веденному пользователем не может быть открыт или не существует;
«Ошибка. Не может быть создан вспомогательный файл» – на жестком диске не достаточно места для создания вспомогательного файла;
Заключение.
В результате выполнения курсового проекта была создана полностью функционирующая программа, решающая поставленную задачу.
Список использованных источников
В. С. Новичков, Н. И. Парфилова, А. Н. Пылькин «Алгоритмизация и программирование на Турбо Паскале»
В. В. Фаронов «Турбо Паскаль 7.0»
Вирт Н. «Алгоритмы и структуры данных»
Н. Культин «Турбо Паскаль в задачах и примерах.»
Приложение.
Исходный текст программы.
Program dec;
Uses crt;
Type
Ptrt=^kos;
kos=Record
pod:string;
Sm:longint;
Next:ptrt;
End;
Var
Put:string;
F:text;
Pfirst:ptrt;
function poisk(var f:text;s2:string;h:real):ptrt;
var
cifra,dopsim,znaki:set of char;
s1:string;
c:char;
x2,control,l,n,k,err,i,ll,hnew,gsum,q,vib1:integer;
dr:real;
phelp:ptrt;
BEGIN
gsum:=0;
reset(f);
control:=0;
DopSim:=['A'..'z','-','А'..'я'];
znaki:=['.',',',';',':','?','?','!'];
n:=0;
pfirst:=nil;
phelp:=nil;
writeln('Введите 1, если хотите различать строчные и прописные буквы, и 0, если не хотите ');
read(vib1);
while not(eof(f)) do
begin
read(f,c);
n:=n+1;
s1:='';
if (c in DopSim) then
begin
s1:='';
while (c in DopSim)and (c<>' ')and(not (c in znaki)) do
begin
s1:=concat(s1,c);
read(f,c);
n:=n+1;
end;
begin
q:=0;
if length(s1)<=length(s2) then ll := length(s1)
else ll:=length(s2);
if vib1= 1 then
begin
for i := 1 to ll do
if s1[i] =s2[i] then q:=q+1;
end else
begin
for i := 1 to ll do
if Upcase(s1[i]) =Upcase(s2[i]) then q:=q+1;
end;
if (q/ll) >= h
then
begin
gsum:=gsum+1;
if pfirst<> nil then
begin
new(phelp^.next);
phelp:=phelp^.next;
end
else
New(phelp);
phelp^.pod:=s1;
phelp^.sm:=n-1-length(s1);
control:=1;
phelp^.next:=nil;
if pfirst=nil then pfirst:=phelp;
n:=1;
end;
end;
end;
end;
if control=0 then poisk:=nil
else
poisk:=pfirst;
close(f);
writeln('Chislo vhojdenij dannoj podstroki = ',gsum);
end;
{----------------------------------------}
procedure liberate(first:ptrt);
var
help:ptrt;
begin
if first<>nil then
begin
while (first^.next<>nil) do
begin
help:=first;
first:=first^.next;
dispose(help);
end;
dispose(first);
end;
end;
{--------------------------------------------------------}
procedure output(var f:text; pfirst:ptrt; s3:string);
var
f2:text;
i:integer;
c:char;
phelp:ptrt;
begin
assign(f2,'led.txt');
rewrite(f2);
reset(f);
if IOResult<>0 then
begin
writeln('Ошибка. Не может быть создан вспомогательный файл');
readln;
end
else
begin
repeat
read(f,c);
write(f2,c);
until eof(f);
close(f2);
close(f);
reset(f2);
rewrite(f);
phelp:=pfirst;
while phelp<>nil do
begin
for i:=1 to phelp^.sm do
begin
read(f2,c);
write(f,c);
end;
write(f,s3);
for i:=1 to length(phelp^.pod) do
read(f2,c);
phelp:=phelp^.next;
end;
while not eof(f2) do
begin
read(f2,c);
write(f,c);
end;
close(f2);
close(f);
reset(f);
while not (eof(f)) do
begin
read(f,c);
write(c);
end;
readkey;
close(f);
erase(f2);
end;
end;
{--------------------------------------------------------}
procedure vozvrat(var f:text;pfirst:ptrt;s3:string);
var
f1:text;
c:char;
phelp:ptrt;
i:integer;
Begin
assign(f1,'led.txt');
rewrite(f1);
reset(f);
if IOResult<>0 then
begin
writeln('Ошибка. Не может быть создан вспомогательный файл');
readln;
end
else
begin
repeat
read(f,c);
write(f1,c);
until eof(f);
close(f1);
close(f);
reset(f1);
rewrite(f);
phelp:=pfirst;
while phelp<>nil do
begin
for i:=1 to phelp^.sm do
begin
read(f1,c);
write(f,c);
end;
write(f,phelp^.pod);
for i:=1 to length(s3) do
read(f1,c);
phelp:=phelp^.next;
end;
while not eof(f1) do
begin
read(f1,c);
write(f,c);
end;
close(f1);
close(f);
erase(f1);
end;
end;
{---------------------------------------------------}
var
s2,s3:string;
h,vib2:real;
BEGIN
clrscr;
writeln('Vvedite put k failu');
readln(put);
writeln('Vvedite stroku dla poisca');
readln(s2);
writeln('Vvedite stroku dla zameni');
readln(s3);
writeln('Vvedite procent sovpadenia');
readln(h);
assign(f,put);
pfirst:=poisk(f,s2,h);
if pfirst<>nil then
output(f,pfirst,s3);
writeln(' ');
writeln('Vvedite 1, esli hotite vipolnit zamenu,i 0 - esli ne hotite');
readln (vib2);
if vib2 = 0 then begin
if pfirst<>nil then
vstavka(f,pfirst,s3)
else writeln('Net ni odnogo vhojdeniya');
end;
if pfirst<>nil then
liberate(pfirst);
END.
|