Идёт загрузка страницы...

htp://aptem.net.ru





Поиск текста в текстовом файле

Кто-нибудь знает быстрый способ поиска строки в текстовом файле?


    unit BMSearch;


(* -------------------------------------------------------------------
Поиск строки методом Boyer-Moore.

Это - один из самых быстрых алгоритмов поиска строки.
See a description in:

R. Boyer и S. Moore.
Быстрый алгоритм поиска строки.
Communications of the ACM 20, 1977, страницы 762-772
------------------------------------------------------------------- *)



interface

type

{$ifdef WINDOWS}
size_t = Word;
{$else}
size_t = LongInt;
{$endif}

type
TTranslationTable = array[char] of char;  { таблица перевода }

TSearchBM = class(TObject)
private
FTranslate  : TTranslationTable;     { таблица перевода }
FJumpTable  : array[char] of Byte;   { таблица переходов }
FShift_1    : integer;
FPattern    : pchar;
FPatternLen : size_t;

public
procedure Prepare( Pattern: pchar; PatternLen: size_t; IgnoreCase: Boolean );
procedure PrepareStr( const Pattern: string; IgnoreCase: Boolean );

function  Search( Text: pchar; TextLen: size_t ): pchar;
function  Pos( const S: string ): integer;
end;




implementation


uses
  SysUtils;



(* -------------------------------------------------------------------
Игнорируем регистр таблицы перевода
------------------------------------------------------------------- *)

procedure CreateTranslationTable( var T: TTranslationTable; IgnoreCase: Boolean );
var
c: char;
begin
for c := #0 to #255 do
T[c] := c;

if not IgnoreCase then
exit;

for c := 'a' to 'z' do
T[c] := UpCase(c);

{ Связываем все нижние символы с их эквивалентом верхнего регистра }

T['Б'] := 'A';
T['А'] := 'A';
T['Д'] := 'A';
T['В'] := 'A';

T['б'] := 'A';
T['а'] := 'A';
T['д'] := 'A';
T['в'] := 'A';

T['Й'] := 'E';
T['И'] := 'E';
T['Л'] := 'E';
T['К'] := 'E';

T['й'] := 'E';
T['и'] := 'E';
T['л'] := 'E';
T['к'] := 'E';

T['Н'] := 'I';
T['М'] := 'I';
T['П'] := 'I';
T['О'] := 'I';

T['н'] := 'I';
T['м'] := 'I';
T['п'] := 'I';
T['о'] := 'I';

T['У'] := 'O';
T['Т'] := 'O';
T['Ц'] := 'O';
T['Ф'] := 'O';

T['у'] := 'O';
T['т'] := 'O';
T['ц'] := 'O';
T['ф'] := 'O';

T['Ъ'] := 'U';
T['Щ'] := 'U';
T['Ь'] := 'U';
T['Ы'] := 'U';

T['ъ'] := 'U';
T['щ'] := 'U';
T['ь'] := 'U';
T['ы'] := 'U';

T['с'] := 'С';
end;



(* -------------------------------------------------------------------
Подготовка таблицы переходов
------------------------------------------------------------------- *)


procedure TSearchBM.Prepare( Pattern: pchar; PatternLen: size_t;
IgnoreCase: Boolean );
var
i: integer;
c, lastc: char;
begin
FPattern := Pattern;
FPatternLen := PatternLen;

if FPatternLen < 1 then
FPatternLen := strlen(FPattern);

{ Данный алгоритм базируется на наборе из 256 символов }

if FPatternLen > 256 then
exit;


{ 1. Подготовка таблицы перевода }

CreateTranslationTable( FTranslate, IgnoreCase);


{ 2. Подготовка таблицы переходов }

for c := #0 to #255 do
FJumpTable[c] := FPatternLen;

for i := FPatternLen - 1 downto 0 do begin
c := FTranslate[FPattern[i]];
if FJumpTable[c] >= FPatternLen - 1 then
FJumpTable[c] := FPatternLen - 1 - i;
end;

FShift_1 := FPatternLen - 1;
lastc := FTranslate[Pattern[FPatternLen - 1]];

for i := FPatternLen - 2 downto 0 do
if FTranslate[FPattern[i]] = lastc  then begin
FShift_1 := FPatternLen - 1 - i;
break;
end;

if FShift_1 = 0 then
FShift_1 := 1;
end;


procedure TSearchBM.PrepareStr( const Pattern: string; IgnoreCase: Boolean );
var
str: pchar;
begin
if Pattern <> '' then begin
{$ifdef Windows}
str := @Pattern[1];
{$else}
str := pchar(Pattern);
{$endif}

Prepare( str, Length(Pattern), IgnoreCase);
end;
end;



{ Поиск последнего символа & просмотр справа налево }

function TSearchBM.Search( Text: pchar; TextLen: size_t ): pchar;
var
shift, m1, j: integer;
jumps: size_t;
begin
result := nil;
if FPatternLen > 256 then
exit;

if TextLen < 1 then
TextLen := strlen(Text);


m1 := FPatternLen - 1;
shift := 0;
jumps := 0;

{ Поиск последнего символа }

while jumps <= TextLen do begin
Inc( Text, shift);
shift := FJumpTable[FTranslate[Text^]];
while shift <> 0 do begin
Inc( jumps, shift);
if jumps > TextLen then
exit;

Inc( Text, shift);
shift := FJumpTable[FTranslate[Text^]];
end;

{ Сравниваем справа налево FPatternLen - 1 символов }

if jumps >= m1 then begin
j := 0;
while FTranslate[FPattern[m1 - j]] = FTranslate[(Text - j)^] do begin
Inc(j);
if j = FPatternLen then begin
result := Text - m1;
exit;
end;
end;
end;

shift := FShift_1;
Inc( jumps, shift);
end;
end;


function TSearchBM.Pos( const S: string ): integer;
var
str, p: pchar;
begin
result := 0;
if S <> '' then begin
{$ifdef Windows}
str := @S[1];
{$else}
str := pchar(S);
{$endif}

p := Search( str, Length(S));
if p <> nil then
result := 1 + p - str;
end;
end;

end.

[000305]