Sources
Delphi Russian Knowledge Base
DRKB - это самая большая и удобная в использовании база знаний по Дельфи в рунете, составленная Виталием Невзоровым

Как реализовать поиск, замену

01.01.2007
procedure TForm1.Button1Click(Sender: TObject);
begin
 
if OpenDialog1.Execute then
    Memo1
.Lines.LoadFromFile(OpenDialog1.FileName);
end;
 
procedure TForm1
.Button2Click(Sender: TObject);
var
  find
: string;
  text
: string;
  st
, len: integer;
  res
: integer;
begin
 
if Memo1.SelStart >= Length(Memo1.Text) then
    Memo1
.SelStart := 0;
  st
:= Memo1.SelStart + 1;
 
if (Memo1.SelLength <= 0) or (not CheckBox1.Checked) then
 
begin
    inc
(st, Memo1.SelLength);
    len
:= Length(Memo1.Text) - st;
 
end
 
else
    len
:= Memo1.SelLength;
  text
:= copy(Memo1.Text, st, len);
  find
:= Edit1.Text;
  res
:= pos(find, text);
 
if res = 0 then
 
begin
   
ShowMessage('Search string "' + find + '" not found');
   
Exit;
 
end;
  Memo1
.SelStart := res + st - 2;
  Memo1
.SelLength := length(find);
end;
 

https://delphiworld.narod.ru/

DelphiWorld 6.0

 

 


Поиск и замена текста в TMemo

procedure TForm1.FindDialog1Find(Sender: TObject);
var
 
Buff, P, FT: PChar;
 
BuffLen: Word;
begin
 
with Sender as TFindDialog do
 
begin
   
GetMem(FT, Length(FindText) + 1);
   
StrPCopy(FT, FindText);
   
BuffLen := Memo1.GetTextLen + 1;
   
GetMem(Buff, BuffLen);
    Memo1
.GetTextBuf(Buff, BuffLen);
    P
:= Buff + Memo1.SelStart + Memo1.SelLength;
    P
:= StrPos(P, FT);
   
if P = nil then
     
MessageBeep(0)
   
else
   
begin
      Memo1
.SelStart := P - Buff;
      Memo1
.SelLength := Length(FindText);
   
end;
   
FreeMem(FT, Length(FindText) + 1);
   
FreeMem(Buff, BuffLen);
 
end;
end;
 
procedure TForm1
.ReplaceDialog1Replace(Sender: TObject);
begin
 
with Sender as TReplaceDialog do
   
while True do
   
begin
     
if Memo1.SelText <> FindText then
        FindDialog1Find
(Sender);
     
if Memo1.SelLength = 0 then
       
Break;
      Memo1
.SelText := ReplaceText;
     
if not (frReplaceAll in Options) then
       
Break;
   
end;
end;

https://delphiworld.narod.ru/

DelphiWorld 6.0


{ **** UBPFD *********** by delphibase.endimus.com ****
>> Поиск и замена текста в поле МЕМО программно
 
На форму бросьте кнопку и поле МЕМО
напишите в МЕМО(в первой строке) текст и поставьте C:\, нажмите кнопку,
при этом C:\ замениться на D:\ без потери форматирования
Вот и все...
 
Зависимости: Смотрите uses
Автор:       Mirag, wwwMirage@yandex.ru, Mirag
Copyright:   Mirag
Дата:        15 ноября 2002 г.
***************************************************** }
 
unit Unit1
;
 
interface
 
uses
 
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 
Dialogs, StdCtrls;
 
type
  TForm1
= class(TForm)
    Button1
: TButton;
    Label1
: TLabel;
    Memo1
: TMemo;
    procedure Button1Click
(Sender: TObject);
    procedure
FormCreate(Sender: TObject);
 
private
   
{ Private declarations }
 
public
   
{ Public declarations }
 
end;
 
var
  Form1
: TForm1;
  result
: boolean;
implementation
 
{$R *.dfm}
 
function ReplaceSub(str, sub1, sub2: string): string;
var
  aPos
: Integer;
  rslt
: string;
begin
  aPos
:= Pos(sub1, str);
  rslt
:= '';
 
while (aPos <> 0) do
 
begin
    rslt
:= rslt + Copy(str, 1, aPos - 1) + sub2;
   
Delete(str, 1, aPos + Length(sub1) - 1);
    aPos
:= Pos(sub1, str);
 
end;
 
Result := rslt + str;
end;
 
function MatchStrings(source, pattern: string): Boolean;
var
 
  pSource
: array[0..255] of Char;
  pPattern
: array[0..255] of Char;
 
 
function MatchPattern(element, pattern: PChar): Boolean;
 
   
function IsPatternWild(pattern: PChar): Boolean;
   
var
      t
: Integer;
   
begin
     
Result := StrScan(pattern, '*') <> nil;
     
if not Result then
       
Result := StrScan(pattern, '?') <> nil;
   
end;
 
 
begin
   
if 0 = StrComp(pattern, '*') then
     
Result := True
   
else if (element^ = Chr(0)) and (pattern^ <> Chr(0)) then
     
Result := False
   
else if element^ = Chr(0) then
     
Result := True
   
else
   
begin
     
case pattern^ of
       
'*': if MatchPattern(element, @pattern[1]) then
           
Result := True
         
else
           
Result := MatchPattern(@element[1], pattern);
       
'?': Result := MatchPattern(@element[1], @pattern[1]);
     
else
       
if element^ = pattern^ then
         
Result := MatchPattern(@element[1], @pattern[1])
       
else
         
Result := False;
     
end;
   
end;
 
end;
 
begin
 
 
StrPCopy(pSource, source);
 
StrPCopy(pPattern, pattern);
 
Result := MatchPattern(pSource, pPattern);
end;
 
procedure TForm1
.Button1Click(Sender: TObject);
var
  ss
: string;
begin
  result
:= MatchStrings(memo1.Lines.Text, '*c:\*');
 
if result = true then
 
begin
    messagebox
(0, '', '', MB_OK);
    ss
:= ReplaceSub(memo1.Lines.Strings[0], 'c:\', 'd:\');
    memo1.Lines.Delete(0);
    memo1.Lines.Insert(0, ss);
  end;
end;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
 
end;
 
end.
 
 
 
 


{ **** UBPFD *********** by delphibase.endimus.com ****
>> Поиск строки в редакторе Memo
 
Зависимости: Windows, Classes, StdCtrls
Автор:       Fenik, chook_nu@uraltc.ru, Новоуральск
Copyright:   Автор: Федоровских Николай
Дата:        26 июня 2002 г.
***************************************************** }
 
function FindInMemo(Memo: TMemo; const FindText: string;
 
FindDown, MatchCase: Boolean): Boolean;
 
{Если строка найдена, то результат True, иначе - False;
 
 
FindText : искомая строка;
 
FindDown : True - поиск вниз от курсора ввода;
             
False - поиск вверх от курсора ввода;
 
MatchCase : True - с учетом регистра букв,
             
False - не учитывая регистр бук.
 
 
Если у Memo стоит автоперенос слов, то могут
 
возникнуть проблемы - текст будет найден,
 
но выделен не там где надо. Так что, для нормального поиска
 
свойство ScrollBars у Memo ставить в ssBoth (ну или ssHorizontal)}
 
 
function PosR2L(const FindStr, SrcStr: string): Integer;
   
{Поиск последнего вхождения подстроки FindStr в строку SrcStr}
 
var
    ps
, L: Integer;
 
   
function InvertSt(const S: string): string;
     
{Инверсия строки S}
   
var
      i
: Integer;
   
begin
      L
:= Length(S);
     
SetLength(Result, L);
     
for i := 1 to L do
       
Result[i] := S[L - i + 1];
   
end;
 
 
begin
    ps
:= Pos(InvertSt(FindStr), InvertSt(SrcStr));
   
if ps <> 0 then
     
Result := Length(SrcStr) - Length(FindStr) - ps + 2
   
else
     
Result := 0;
 
end;
 
 
function MCase(const s: string): string;
   
{Перевод заглавных букв в строчные;
     
Функция вызывается если регистр не учитывается}
 
var
    i
: Integer;
 
begin
   
Result := s;
   
for i := 1 to Length(s) do
   
begin
     
case s[i] of
       
'A'..'Z',
         
'А'..'Я': Result[i] := Chr(Ord(s[i]) + 32);
       
'Ё': Result[i] := 'ё';
       
'Ѓ': Result[i] := 'ѓ';
       
'Ґ': Result[i] := 'ґ';
       
'Є': Result[i] := 'є';
       
'Ї': Result[i] := 'ї';
       
'І': Result[i] := 'і';
       
'Ѕ': Result[i] := 'ѕ';
     
end;
   
end;
 
end;
 
var
  Y
, X, SkipChars: Integer;
 
FindS, SrcS: string;
  P
: TPoint;
begin
 
Result := False;
 
 
if MatchCase then
   
FindS := FindText
 
else
   
FindS := MCase(FindText);
 
  P
:= Memo.CaretPos;
 
 
if FindDown then
   
{Поиск вправо и вниз от курсора ввода}
   
for Y := P.y to Memo.Lines.Count do
   
begin
 
     
if Y <> P.y then
       
{Если это не строка, в которой курсор вода,
         
то ищем во всей строке}
       
SrcS := Memo.Lines[Y]
     
else
       
{иначе обрезаем строку от курсора до конца}
       
SrcS := Copy(Memo.Lines[Y], P.x + 1,
         
Length(Memo.Lines[Y]) - P.x + 1);
 
     
if not MatchCase then
       
SrcS := MCase(SrcS);
      X
:= Pos(FindS, SrcS);
     
if X <> 0 then
     
begin
       
if Y = P.y then
         
Inc(X, P.x);
        P
:= Point(X, Y);
       
Result := True;
       
Break; {Выход из цикла}
     
end
   
end
 
else
   
{Поиск влево и вверх от курсора ввода}
   
for Y := P.y downto 0 do
   
begin
 
     
if Y <> P.y then
       
{Если это не строка, в которой курсор вода,
         
то ищем во всей строке}
       
SrcS := Memo.Lines[Y]
     
else
       
{иначе обрезаем строку от начала до курсора
         
минус выделенный текст}
       
SrcS := Copy(Memo.Lines[Y], 1, P.x - Memo.SelLength);
 
     
if not MatchCase then
       
SrcS := MCase(SrcS);
      X
:= PosR2L(FindS, SrcS);
     
if X <> 0 then
     
begin
        P
:= Point(X, Y);
       
Result := True;
       
Break; {Выход из цикла}
     
end
   
end;
 
 
if Result then
 
begin
   
{Если текст найден - выделяем его}
   
SkipChars := 0;
   
for y := 0 to P.Y - 1 do
     
Inc(SkipChars, Length(Memo.Lines[y]));
   
Memo.SelStart := SkipChars + (P.Y * 2) + P.X - 1;
   
Memo.SelLength := Length(FindText);
 
end;
end;
Пример использования:
 
procedure TForm1
.FindDialog1Find(Sender: TObject);
begin
 
if not FindInMemo(Memo1,
    FindDialog1
.FindText,
    frDown
in FindDialog1.Options,
    frMatchCase
in FindDialog1.Options) then
   
Application.MessageBox('Поиск результатов не дал.',
     
PChar(Application.Title),
      MB_OK
or MB_ICONINFORMATION);
end;
 


Пришло мне письмо от Алексея. На этот раз он прислал (цитирую): "юнит для поиска строки(текста) в TEdit, TMemo, или других компонентах (дочерних TCustomEdit'у)." Так как тескт "авторский" (более того, здесь также присутствует наследование), помещаю его здесь в том виде, в котором он был прислан, т.е. без перевода. В случае каких-либо вопросов и недоразумений обращайтесь по вышеуказанносу адресу электронной почты.

{ПРИМЕР :
 
[...]
 
implementation
 
uses
Search;}
{$R *.DFM}
 
{procedure TForm1.Button1Click(Sender: TObject);
begin
 
SearchMemo(RichEdit1, 'Найди меня', [frDown]);
end;
 
В опции поиска можно подключать, отключать, комбинировать следующие
параметры:
frDown
- указывает на то, что происходит поиск вниз по тексту от курсора(при
отключенном frDown'е будет происходит поиск вверх по тексту).
frMatchCase - указывает на то, что следует проводить поиск с учетом
регистра.
frWholeWord - указывает на то, что следует искать только слово целиком.
 
[...]
 
Авторские права на этот юнит пренадлежат неизвесно кому.
 
В каком виде этот юнит попал мне, практически в этом же
виде я отдаю его вам. Пользуйтесь и благодарите неизвесного
героя.}
 
unit Search;
 
interface
 
uses
 
  WinProcs, SysUtils, StdCtrls, Dialogs;
 
const
  {****************************************************************************
 
  * Default word delimiters are any character except the core alphanumerics. *
  ****************************************************************************}
  WordDelimiters: set of Char = [#0..#255] - ['
a'..'z', 'A'..'Z', '1'..'9',
    '
0'];
  {******************************************************************************
 
  * SearchMemo scans the text of a TEdit, TMemo, or other TCustomEdit-derived  *
  * component for a given search string. The search starts at the current      *
  * caret position in the control.  The Options parameter determines whether   *
  * the search runs forward (frDown) or backward from the caret position,      *
  * whether or not the text comparison is case sensitive, and whether the      *
  * matching string must be a whole word.  If text is already selected in the  *
  * control, the search starts at the '
far end' of the selection (SelStart if  *
  * searching backwards, SelEnd if searching forwards).  If a match is found,  *
  * the control'
s text selection is changed to select the found text and the   *
 
* function returns True.  If no match is found, the function returns False.  *
 
******************************************************************************}
function SearchMemo(Memo: TCustomEdit;
 
 
const SearchString: string;
 
Options: TFindOptions): Boolean;
{******************************************************************************
 
* SearchBuf is a lower-level search routine for arbitrary text buffers.      *
* Same rules as SearchMemo above. If a match is found, the function returns  *
* a pointer to the start of the matching string in the buffer. If no match,  *
* the function returns nil.                                                  *
******************************************************************************}
function SearchBuf(Buf: PChar; BufLen: Integer;
 
 
SelStart, SelLength: Integer;
 
SearchString: string;
 
Options: TFindOptions): PChar;
 
implementation
 
function SearchMemo(Memo: TCustomEdit;
 
 
const SearchString: string;
 
Options: TFindOptions): Boolean;
var
 
 
Buffer, P: PChar;
 
Size: Word;
begin
 
 
Result := False;
 
if (Length(SearchString) = 0) then
   
Exit;
 
Size := Memo.GetTextLen;
 
if Size = 0 then
   
Exit;
 
Buffer := StrAlloc(Size + 1);
 
try
   
Memo.GetTextBuf(Buffer, Size + 1);
    P
:= SearchBuf(Buffer, Size, Memo.SelStart, Memo.SelLength, SearchString,
     
Options);
   
if P <> nil then
   
begin
     
Memo.SelStart := P - Buffer;
     
Memo.SelLength := Length(SearchString);
     
Result := True;
   
end;
 
finally
   
StrDispose(Buffer);
 
end;
end;
 
function SearchBuf(Buf: PChar; BufLen: Integer;
 
 
SelStart, SelLength: Integer;
 
SearchString: string;
 
Options: TFindOptions): PChar;
var
 
 
SearchCount, I: Integer;
  C
: Char;
 
Direction: Shortint;
 
CharMap: array[Char] of Char;
 
 
function FindNextWordStart(var BufPtr: PChar): Boolean;
 
begin { (True XOR N) is equivalent to (not N) }
   
//    Result := False;      { (False XOR N) is equivalent to (N)    }
 
   
{ When Direction is forward (1), skip non delimiters, then skip delimiters. }
   
{ When Direction is backward (-1), skip delims, then skip non delims }
 
   
while (SearchCount > 0) and
     
((Direction = 1) xor
     
(BufPtr^ in WordDelimiters)) do
   
begin
     
Inc(BufPtr, Direction);
     
Dec(SearchCount);
   
end;
 
   
while (SearchCount > 0) and
     
((Direction = -1) xor
     
(BufPtr^ in WordDelimiters)) do
   
begin
     
Inc(BufPtr, Direction);
     
Dec(SearchCount);
   
end;
 
   
Result := SearchCount > 0;
   
if Direction = -1 then
   
begin {back up one char, to leave ptr on first non delim}
     
Dec(BufPtr, Direction);
     
Inc(SearchCount);
   
end;
 
end;
 
begin
 
 
Result := nil;
 
 
if BufLen <= 0 then
   
Exit;
 
 
if frDown in Options then
 
begin {if frDown...}
   
Direction := 1;
   
Inc(SelStart, SelLength); { start search past end of selection }
   
SearchCount := BufLen - SelStart - Length(SearchString);
 
   
if SearchCount < 0 then
     
Exit;
 
   
if Longint(SelStart) + SearchCount > BufLen then
     
Exit;
 
 
end {if frDown...}
 
else
 
begin {else}
   
Direction := -1;
   
Dec(SelStart, Length(SearchString));
   
SearchCount := SelStart;
 
end; {else}
 
 
if (SelStart < 0) or (SelStart > BufLen) then
   
Exit;
 
 
Result := @Buf[SelStart];
 
{ Using a Char map array is faster than calling AnsiUpper on every character }
 
 
for C := Low(CharMap) to High(CharMap) do
   
CharMap[C] := C;
 
 
if not (frMatchCase in Options) then
 
begin {if not (frMatchCase}
   
AnsiUpperBuff(PChar(@CharMap), sizeof(CharMap));
   
AnsiUpperBuff(@SearchString[1], Length(SearchString));
 
end; {if not (frMatchCase}
 
 
while SearchCount > 0 do
 
begin {while SearchCount}
   
if frWholeWord in Options then
   
begin
     
if not FindNextWordStart(Result) then
       
Break;
   
end;
    I
:= 0;
 
   
while (CharMap[Result[I]] = SearchString[I + 1]) do
   
begin {while (CharMap...}
     
Inc(I);
     
if I >= Length(SearchString) then
     
begin {if I >=...}
       
if (not (frWholeWord in Options)) or
         
(SearchCount = 0) or
         
(Result[I] in WordDelimiters) then
         
Exit;
       
Break;
     
end; {if I >=...}
   
end; {while (CharMap...}
 
   
Inc(Result, Direction);
   
Dec(SearchCount);
 
end; {while SearchCount}
 
 
Result := nil;
end;
 
end.
 
 
 

https://delphiworld.narod.ru/

DelphiWorld 6.0