Code: |
{ПРИМЕР :
[...]
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.
|
- << Назад
- Вперёд
Просьба писать ваши замечания, наблюдения и все остальное,
что поможет улучшить предоставляемую информацию на этом сайте.
ВСЕ КОММЕНТАРИИ МОДЕРИРУЮТСЯ ВРУЧНУЮ, ТАК ЧТО СПАМИТЬ БЕСПОЛЕЗНО!