Консультация № 175059
09.12.2009, 07:23
35.00 руб.
0 8 1
Пользуюсь процедурой для поиска и замены по документу, но в том случае если искомый параметр в документе указан не один раз то он заменяет мне все находимые слова по документу подскажите как переделать процедуру чтобы она не повсему документу заменяла а по определенному участку скажем между 2 закладками

Приложение:
пример - содержимое файла:
--
прив
закладка1
прив
закладка2
прив
--
FileRep(Edit2.Text, 'прив' , 'привет');
после исполнения процедуры
--
привет
закладка1
привет
закладка2
привет
--
Мне надо:

FileRep(Edit2.Text, 'прив' , 'привет', 'закладка1', 'Закладка2');
после исполнения процедуры
--
прив
закладка1
привет
закладка2
прив




procedure FileRep(const FileName, searchstring, replacestring: string);
var
fs1: TfileStream;
S: string;
begin
fs1 := TFileStream.Create(FileName, fmOpenread or fmShareDenyNone);
try
SetLength(S, fs1.Size);
fs1.ReadBuffer(S[1], fs1.Size);
finally
fs1.Free;
end;
S := StringReplace(S, SearchString, replaceString, [rfReplaceAll, rfIgnoreCase]);
fs1 := TFileStream.Create(filename, fmCreate);
try
fs1.WriteBuffer(S[1], Length(S));
finally
fs1.Free;
end;
end;

Обсуждение

давно
Мастер-Эксперт
425
4118
09.12.2009, 09:02
общий
Kensh1n:
1. Документ чисто текстовый? Не word, не excel и не какие-нибудь там pdf'ы с djvu'ками?
2. Закладка - это слово "Закладка" плюс её номер? Каков принцип создания закладок?

Об авторе:
Я только в одном глубоко убеждён - не надо иметь убеждений! :)
Неизвестный
09.12.2009, 11:32
общий
sir Henry:
1. ртф шаблон в ворде формирую
2. ставлю закладки в ворде перед каждой таблицей table2,table3...

данной функицей хочу я заменить слово в таблице wher на where, получаю замену слова по всему документу а не только в таблице
Неизвестный
09.12.2009, 12:35
общий
StringReplace возвращает копию S, где OldSubStr заменена на NewSubStr. Если Flags содержит rfReplaceAll, заменяются все вхождения OldSubStr; иначе заменяется только первое вхождение. Поиск OldSubStr выполняется с учетом регистра, если только не включен флаг rflgnoreCase
----
выходит для данного примера эту функцию нужно выкинуть? как тогда замутить?
Неизвестный
09.12.2009, 12:47
общий
щас что-нить сваяю, подожди...
Неизвестный
09.12.2009, 13:08
общий
10.12.2009, 18:07
это ответ
Здравствуйте, Kensh1n.
На сколько я понял, расширение документа у тебя ".rtf". Документы в формате RTF сохраняются в виде обогащенного, а не обычного текста. Подробнее о структуре можешь посмотреть тут. Впринцыпе, твоим методом можно заменять слова в таком тексте, но это опасно, т.к. можно случайно заменить тэги и тогда структура документа испортится. Для примера открой свой rtf файл обычным блокнотом. Ты увидишь там много разнообразных тэгов. Чтоб не испортить структуру документа, можно сделать алгоритм игнорирования тегов и замены только в тексте. Но, можно зделать попроще. Если хорошо посмотреть, то видно, что закладки в документе rtf обозначаются тэгами {\*\bkmkstart zakladka}{\*\bkmkend zakladka}, где zakladka - имя закладки. И тогда надо будет немного расширить твою процедуру, например так (смотри во вложении). bkmName1 и bkmName2 - это имена первой и второй закладок (между которыми надо заменять).
P.S. Еще могу посоветовать замену не между двух закладок, а внутри одной. В ворде надо выделить таблицу, и сделать её полностью закладкой. В процедуре надо будет искать позиции не открывающих тегов двух закладок, а открывающего (\bkmkstart) и закрывающего (\bkmkend) тега одной закладки. И указывать надо будет не 2 закладки, а одну (мне кажется так проще). Но это уже твоё дело.

Приложение:
procedure FileRep(const FileName, searchstring, replacestring: string;
const bkmName1, bkmName2:string);
var
fs1: TfileStream;
S: string;
S1, S2:string;
n1, n2:integer;
begin
// Читаем из файла в S
fs1 := TFileStream.Create(FileName, fmOpenread or fmShareDenyNone);
try
SetLength(S, fs1.Size);
fs1.ReadBuffer(S[1], fs1.Size);
finally
fs1.Free;
end;
// режем текст на 3 части: в первой текст до первой закладки
// во второй от первой до второй
// в третьей от второй до конца файла
n1:=Pos('\bkmkstart '+bkmName1, S); // Ищем первую закладку
if n1=0 then
begin
ShowMessage('В документе нет закладки "'+bkmName1+'"');
Exit;
end;
n1:=n1+Length('\bkmkstart '+bkmName1); // Смещаем, чтоб не заменять внутри тега закладки (не принципиально)
n2:=Pos('\bkmkstart '+bkmName2, S); // Ищем вторую закладку
if n2=0 then
begin
ShowMessage('В документе нет закладки "'+bkmName2+'"');
Exit;
end;
S1:=copy(S, 1, n1-1); // Достаём первую часть
S2:=copy(S, n2, Length(S)-n2+1); // Достаём последнюю часть
S:=copy(S, n1, n2-n1); // Средняя часть (в которой будем заменять)
S:=StringReplace(S, SearchString, replaceString, [rfReplaceAll, rfIgnoreCase]); // Замена только в тексте меж закладками
// Склеиваем обратно в одну строку
S:=S1+S+S2;
// Пишем обратно в файл
fs1 := TFileStream.Create(filename, fmCreate);
try
fs1.WriteBuffer(S[1], Length(S));
finally
fs1.Free;
end;
end;
// Протестировал у себя на Delphi 7 и Word 2007. Всё работает в пределах допустимого. :-)
Неизвестный
09.12.2009, 13:12
общий
посмотреть тут.

и когда у меня ссылки начнут работать...
Неизвестный
09.12.2009, 13:53
общий
Kensh1n:
В вопросе вы написали, что хотите произвесит замену между двумя закладками:
FileRep(Edit2.Text, 'прив' , 'привет', 'закладка1', 'Закладка2');
после исполнения процедуры --
прив
закладка1
привет
закладка2
прив

Я Вам зделал процедуру, которая это самое и делает. Щас вы говорите, про какието 3 таблицы и ни слова о закладках, которые Вы, якобы, проставили перед и после таблиц, в которых надо производить замену.
Если вариант с закладками отпадает, то можно щитать кол-во открывающих и закрывающих тэгов таблиц и производить замену только во второй (или какой-то там) по счёту таблице, если номер таблицы известен заранее. А функция StringReplace тут не причём. Нужно лишь применять её для того текста, в котором хочешь заменять. А этот текст вытаскивать из основного текста по своему алгоритму, как тебе надо.
Неизвестный
09.12.2009, 15:18
общий
Alex1:
извиняюсь что то я видимо заработался под конец дня, просто ваше словесное описание меня немножко сбило с толку, щас повнимательнее посмотрел текст процедуры все так как надо еще раз сори!
Форма ответа