Добро пожаловать,
Поиск
Представляю на Ваш суд утилиту быстрого поиска по базе данных. Данная технология производит поиск по полям, преобразуя их значения в строки (все значения преобразуются в верхний регистр, включая действительные числа).
Данное решение может быть не самым быстрым, однако на поверку оно оказывается быстрее остальных, обнаруженных мною в Интернете (может вам повезет больше). Более того, представьте, что действительное значение какого-либо поля равно 4.509375354, а значение поиска равно 7, в этом случае утилита засчитает "попадание". Утилита удобна также тем, что она за один проход производит поиск более, чем в одном поле.
Это удобно, если у Вас имеются, к примеру, два поля с адресами. Это моя первая "серьезная" разработка, так как первое, с чем я столкнулся, изучая Delphi, стала необходимость включения процедуры поиска в любое приложение, работающее с базой данных. А так как поиск - вещь тоже сугубо специфическая, как и любое приложение, то мне пришлось побороть свой страх перед "крутым программированием" и попробовать написать свой поисковый механизм, удовлетворивший меня (и, надеюсь, других) своей скоростью и возможностью "мульти"-поиска по нескольким полям.
Я надеюсь, что он поможет тем программистам, кто часто сталкивается с подобными задачами. Технология довольно легка для понимания, но если у Вас возникли какие-либо вопросы, пошлите мне письмо электронной почтой, я буду рад Вам помочь. Посмотрев код, можно легко узнать поддерживаемые типы полей (добавить новые не составит проблем).
Код unit Finder;
interface
uses DB, DBTables, SysUtils;
function GrabMemoFieldAsPChar(TheField : TMemoField): PChar;
function DoFindIn(TheField : TField; SFor : String): Boolean;
function FindIt(TheTable : TDataSet; TheFields : array of integer;
SearchBackward : Boolean; Beginning : Boolean; SFor : String): Boolean;
{применение функции FindIt -
if FindIt(NotesSearchT,
[NotesSearchT.FieldByName('Leadman').Index],
False, True, SearchText.Text) then DoSomething; }
implementation
function GrabMemoFieldAsPChar(TheField : TMemoField): PChar;
begin
with TBlobStream.Create(TheField, bmRead) do
begin
GetMem(Result, Size + 1);
FillChar(Result^, Size + 1, #0);
Read(Result^, Size);
Free;
end;
end;
function DoFindIn(TheField : TField; SFor : String): Boolean;
var
PChForMemo : PChar;
begin
Result := False;
case TheField.DataType of
ftString :
begin
if (Pos(SFor, UpperCase(TheField.AsString)) > 0) then
Result := True;
end;
ftInteger :
begin
if (Pos(SFor, TheField.AsString) > 0) then Result := True;
end;
ftBoolean :
begin
if SFor = UpperCase(TheField.AsString) then
Result := True;
end;
ftFloat :
begin
if (Pos(SFor, TheField.AsString) > 0) then Result := True;
end;
ftCurrency :
begin
if (Pos(SFor, TheField.AsString) > 0) then Result := True;
end;
ftDate .. ftDateTime :
begin
if (Pos(SFor, TheField.AsString) > 0) then Result := True;
end;
ftMemo :
begin
SFor[Ord(SFor[0]) + 1] := #0;
PChForMemo := GrabMemoFieldAsPChar(TMemoField(TheField));
StrUpper(PChForMemo);
if not (StrPos( PChForMemo, @SFor[1] ) = nil) then Result :=
True; FreeMem(PChForMemo, StrLen(PChForMemo + 1));
end;
end;
end;
function FindIt(TheTable : TDataSet; TheFields : array of integer;
SearchBackward : Boolean; Beginning : Boolean; SFor : String): Boolean;
var
i, HighTheFields, LowTheFields : integer;
BM : TBookmark;
begin
TheTable.DisableControls;
BM := TheTable.GetBookmark;
try
LowTheFields := Low(TheFields);
HighTheFields := High(TheFields);
SFor := UpperCase(SFor);
Result := False;
if Beginning then TheTable.First;
if SearchBackward then
begin
TheTable.Prior;
while not TheTable.BOF do
begin
for i := LowTheFields to HighTheFields do
begin
if DoFindIn(TheTable.Fields[TheFields[i]], SFor) then
begin
Result := True;
Break;
end;
end;
if Result then Break else TheTable.Prior;
end;
end else
begin
TheTable.Next;
while not TheTable.EOF do
begin
for i := LowTheFields to HighTheFields do
begin
if DoFindIn(TheTable.Fields[TheFields[i]], SFor) then
begin
Result := True;
Break;
end;
end;
if Result then Break else TheTable.Next;
end;
end;
finally
TheTable.EnableControls;
if not Result then
TheTable.GotoBookmark(BM);
TheTable.FreeBookmark(BM);
end;
end;
end.
Я представляю на Ваш суд утилиту быстрого поиска по базе данных. Данная технология производит поиск по полям, преобразуя их значения в строки (все значения преобразуются в верхний регистр, включая действительные числа).
Данное решение может быть не самым быстрым, однако на поверку оно оказывается быстрее остальных, обнаруженных мною в Интернете (может вам повезет больше). Более того, представьте, что действительное значение какого-либо поля равно 4.509375354, а значение поиска равно 7, в этом случае утилита засчитает "попадание". Утилита удобна также тем, что она за один проход производит поиск более, чем в одном поле.
Это удобно, если у Вас имеются, к примеру, два поля с адресами. Это моя первая "серьезная" разработка, так как первое, с чем я столкнулся, изучая Delphi, стала необходимость включения процедуры поиска в любое приложение, работающее с базой данных. А так как поиск - вещь тоже сугубо специфическая, как и любое приложение, то мне пришлось побороть свой страх перед "крутым программированием" и попробовать написать свой поисковый механизм, удовлетворивший меня (и, надеюсь, других) своей скоростью и возможностью "мульти"-поиска по нескольким полям.
Я надеюсь, что он поможет тем программистам, кто часто сталкивается с подобными задачами. Технология довольно легка для понимания, но если у Вас возникли какие-либо вопросы, пошлите мне письмо электронной почтой, я буду рад Вам помочь. Посмотрев код, можно легко узнать поддерживаемые типы полей (добавить новые не составит проблем).
Код unit Finder;
interface
uses DB, DBTables, SysUtils;
function GrabMemoFieldAsPChar(TheField : TMemoField): PChar;
function DoFindIn(TheField : TField; SFor : String): Boolean;
function FindIt(TheTable : TDataSet; TheFields : array of integer;
SearchBackward : Boolean; Beginning : Boolean; SFor : String): Boolean;
{применение функции FindIt -
if FindIt(NotesSearchT,
[NotesSearchT.FieldByName('Leadman').Index],
False, True, SearchText.Text) then DoSomething; }
implementation
function GrabMemoFieldAsPChar(TheField : TMemoField): PChar;
begin
with TBlobStream.Create(TheField, bmRead) do
begin
GetMem(Result, Size + 1);
FillChar(Result^, Size + 1, #0);
Read(Result^, Size);
Free;
end;
end;
function DoFindIn(TheField : TField; SFor : String): Boolean;
var
PChForMemo : PChar;
begin
Result := False;
case TheField.DataType of
ftString :
begin
if (Pos(SFor, UpperCase(TheField.AsString)) > 0) then
Result := True;
end;
ftInteger :
begin
if (Pos(SFor, TheField.AsString) > 0) then Result := True;
end;
ftBoolean :
begin
if SFor = UpperCase(TheField.AsString) then
Result := True;
end;
ftFloat :
begin
if (Pos(SFor, TheField.AsString) > 0) then Result := True;
end;
ftCurrency :
begin
if (Pos(SFor, TheField.AsString) > 0) then Result := True;
end;
ftDate .. ftDateTime :
begin
if (Pos(SFor, TheField.AsString) > 0) then Result := True;
end;
ftMemo :
begin
SFor[Ord(SFor[0]) + 1] := #0;
PChForMemo := GrabMemoFieldAsPChar(TMemoField(TheField));
StrUpper(PChForMemo);
if not (StrPos( PChForMemo, @SFor[1] ) = nil) then Result :=
True; FreeMem(PChForMemo, StrLen(PChForMemo + 1));
end;
end;
end;
function FindIt(TheTable : TDataSet; TheFields : array of integer;
SearchBackward : Boolean; Beginning : Boolean; SFor : String): Boolean;
var
i, HighTheFields, LowTheFields : integer;
BM : TBookmark;
begin
TheTable.DisableControls;
BM := TheTable.GetBookmark;
try
LowTheFields := Low(TheFields);
HighTheFields := High(TheFields);
SFor := UpperCase(SFor);
Result := False;
if Beginning then TheTable.First;
if SearchBackward then
begin
TheTable.Prior;
while not TheTable.BOF do
begin
for i := LowTheFields to HighTheFields do
begin
if DoFindIn(TheTable.Fields[TheFields[i]], SFor) then
begin
Result := True;
Break;
end;
end;
if Result then Break else TheTable.Prior;
end;
end else
begin
TheTable.Next;
while not TheTable.EOF do
begin
for i := LowTheFields to HighTheFields do
begin
if DoFindIn(TheTable.Fields[TheFields[i]], SFor) then
begin
Result := True;
Break;
end;
end;
if Result then Break else TheTable.Next;
end;
end;
finally
TheTable.EnableControls;
if not Result then
TheTable.GotoBookmark(BM);
TheTable.FreeBookmark(BM);
end;
end;
end.
Вот несколько функций для операций с двухмерными массивами. Самый простой путь для создания собственной библиотеки. Процедуры SetV и GetV позволяют читать и сохранять элементы массива VArray (его Вы можете объявить как угодно).
Например:
Код type
VArray : Array[1..1] of double;
var
X : ^VArray;
NR, NC : Longint;
begin
NR := 10000;
NC := 100;
if AllocArray(pointer(X), N*Sizeof(VArray)) then exit;
SetV(X^, NC, 2000, 5, 3.27); { X[2000,5] := 3.27 }
end;
function AllocArray(var V : pointer; const N : longint) : Boolean;
begin {распределяем память для массива V размера N}
try
GetMem(V, N);
except
ShowMessage('ОШИБКА выделения памяти. Размер:' + IntToStr(N));
Result := True;
exit;
end;
FillChar(V^, N, 0); {в случае включения длинных строк заполняем их нулями}
Result := False;
end;
procedure SetV(var X : Varray;const N,ir,ic : LongInt;const value :
double);
begin {заполняем элементами двухмерный массив X размером ? x N : X[ir,ic] := value}
X[N*(ir-1) + ic] := value;
end;
function GetV(const X : Varray; const N, ir,ic : Longint) : double;
begin {возвращаем величины X[ir,ic] для двухмерного массива шириной N столбцов}
Result := X[N*(ir-1) + ic];
end;
Самый простой путь - создать массив динамически
Код Myarray := GetMem(rows * cols * sizeof(byte,word,single,double и пр.)
сделайте функцию fetch_num типа
Код function fetch_num(r,c:integer) : single;
result := pointer + row + col*rows
и затем вместо myarray[2,3] напишите
Код myarray.fetch_num(2,3)
Вот способ создания одно- и двухмерных динамических массивов:
Код (*
модуль для создания двух очень простых классов обработки динамических массивов
TDynaArray : одномерный массив
TDynaMatrix : двумерный динамический массив
*)
unit DynArray;
INTERFACE
uses
SysUtils;
Type
TDynArrayBaseType = double;
Const
vMaxElements = (High(Cardinal) - $f) div sizeof(TDynArrayBaseType);
{= гарантирует максимально возможный массив =}
Type
TDynArrayNDX = 1..vMaxElements;
TArrayElements = array[TDynArrayNDX] of TDynArrayBaseType;
{= самый большой массив TDynArrayBaseType, который мы может объявить =}
PArrayElements = ^TArrayElements;
{= указатель на массив =}
EDynArrayRangeError = CLASS(ERangeError);
TDynArray = CLASS
Private
fDimension : TDynArrayNDX;
fMemAllocated : word;
Function GetElement(N : TDynArrayNDX) : TDynArrayBaseType;
Procedure SetElement(N : TDynArrayNDX; const NewValue : TDynArrayBaseType);
Protected
Elements : PArrayElements;
Public
Constructor Create(NumElements : TDynArrayNDX);
Destructor Destroy; override;
Procedure Resize(NewDimension : TDynArrayNDX); virtual;
Property dimension : TDynArrayNDX
read fDimension;
Property Element[N : TDynArrayNDX] : TDynArrayBaseType
read GetElement
write SetElement;
default;
END;
Const
vMaxMatrixColumns = 65520 div sizeof(TDynArray);
{= построение матрицы класса с использованием массива объектов TDynArray =}
Type
TMatrixNDX = 1..vMaxMatrixColumns;
TMatrixElements = array[TMatrixNDX] of TDynArray;
{= каждая колонка матрицы будет динамическим массивом =}
PMatrixElements = ^TMatrixElements;
{= указатель на массив указателей... =}
TDynaMatrix = CLASS
Private
fRows : TDynArrayNDX;
fColumns : TMatrixNDX;
fMemAllocated : longint;
Function GetElement( row : TDynArrayNDX;
column : TMatrixNDX) : TDynArrayBaseType;
Procedure SetElement( row : TDynArrayNDX;
column : TMatrixNDX;
const NewValue : TDynArrayBaseType);
Protected
mtxElements : PMatrixElements;
Public
Constructor Create(NumRows : TDynArrayNDX; NumColumns : TMatrixNDX);
Destructor Destroy; override;
Property rows : TDynArrayNDX
read fRows;
Property columns : TMatrixNDX
read fColumns;
Property Element[row : TDynArrayNDX; column : TMatrixNDX] : TDynArrayBaseType
read GetElement
write SetElement;
default;
END;
IMPLEMENTATION
(*
методы TDynArray
*)
Constructor TDynArray.Create(NumElements : TDynArrayNDX);
BEGIN {==TDynArray.Create==}
inherited Create;
fDimension := NumElements;
GetMem( Elements, fDimension*sizeof(TDynArrayBaseType) );
fMemAllocated := fDimension*sizeof(TDynArrayBaseType);
FillChar( Elements^, fMemAllocated, 0 );
END; {==TDynArray.Create==}
Destructor TDynArray.Destroy;
BEGIN {==TDynArray.Destroy==}
FreeMem( Elements, fMemAllocated );
inherited Destroy;
END; {==TDynArray.Destroy==}
Procedure TDynArray.Resize(NewDimension : TDynArrayNDX);
BEGIN {TDynArray.Resize==}
if (NewDimension < 1) then
raise EDynArrayRangeError.CreateFMT('Индекс вышел за границы диапазона : %d', [NewDimension]);
Elements := ReAllocMem(Elements, fMemAllocated, NewDimension*sizeof(TDynArrayBaseType));
fDimension := NewDimension;
fMemAllocated := fDimension*sizeof(TDynArrayBaseType);
END; {TDynArray.Resize==}
Function TDynArray.GetElement(N : TDynArrayNDX) : TDynArrayBaseType;
BEGIN {==TDynArray.GetElement==}
if (N < 1) OR (N > fDimension) then
raise EDynArrayRangeError.CreateFMT('Индекс вышел за границы диапазона : %d', [N]);
result := Elements^[N];
END; {==TDynArray.GetElement==}
Procedure TDynArray.SetElement(N : TDynArrayNDX; const NewValue : TDynArrayBaseType);
BEGIN {==TDynArray.SetElement==}
if (N < 1) OR (N > fDimension) then
raise EDynArrayRangeError.CreateFMT('Индекс вышел за границы диапазона : %d', [N]);
Elements^[N] := NewValue;
END; {==TDynArray.SetElement==}
(*
методы TDynaMatrix
*)
Constructor TDynaMatrix.Create(NumRows : TDynArrayNDX; NumColumns : TMatrixNDX);
Var col : TMatrixNDX;
BEGIN {==TDynaMatrix.Create==}
inherited Create;
fRows := NumRows;
fColumns := NumColumns;
{= выделение памяти для массива указателей (т.е. для массива TDynArrays) =}
GetMem( mtxElements, fColumns*sizeof(TDynArray) );
fMemAllocated := fColumns*sizeof(TDynArray);
{= теперь выделяем память для каждого столбца матрицы =}
for col := 1 to fColumns do
BEGIN
mtxElements^[col] := TDynArray.Create(fRows);
inc(fMemAllocated, mtxElements^[col].fMemAllocated);
END;
END; {==TDynaMatrix.Create==}
Destructor TDynaMatrix.Destroy;
Var col : TMatrixNDX;
BEGIN {==TDynaMatrix.Destroy;==}
for col := fColumns downto 1 do
BEGIN
dec(fMemAllocated, mtxElements^[col].fMemAllocated);
mtxElements^[col].Free;
END;
FreeMem( mtxElements, fMemAllocated );
inherited Destroy;
END; {==TDynaMatrix.Destroy;==}
Function TDynaMatrix.GetElement( row : TDynArrayNDX;
column : TMatrixNDX) : TDynArrayBaseType;
BEGIN {==TDynaMatrix.GetElement==}
if (row < 1) OR (row > fRows) then
raise EDynArrayRangeError.CreateFMT('Индекс строки вышел за границы диапазона : %d', [row]);
if (column < 1) OR (column > fColumns) then
raise EDynArrayRangeError.CreateFMT('Индекс столбца вышел за границы диапазона : %d', [column]);
result := mtxElements^[column].Elements^[row];
END; {==TDynaMatrix.GetElement==}
Procedure TDynaMatrix.SetElement( row : TDynArrayNDX;
column : TMatrixNDX;
const NewValue : TDynArrayBaseType);
BEGIN {==TDynaMatrix.SetElement==}
if (row < 1) OR (row > fRows) then
raise EDynArrayRangeError.CreateFMT('Индекс строки вышел за границы диапазона : %d', [row]);
if (column < 1) OR (column > fColumns) then
raise EDynArrayRangeError.CreateFMT('Индекс столбца вышел за границы диапазона : %d', [column]);
mtxElements^[column].Elements^[row] := NewValue;
END; {==TDynaMatrix.SetElement==}
END.
Тестовая программа для модуля DynArray
uses DynArray, WinCRT;
Const
NumRows : integer = 7;
NumCols : integer = 5;
Var
M : TDynaMatrix;
row, col : integer;
BEGIN
M := TDynaMatrix.Create(NumRows, NumCols);
for row := 1 to M.Rows do
for col := 1 to M.Columns do
M[row, col] := row + col/10;
writeln('Матрица');
for row := 1 to M.Rows do
BEGIN
for col := 1 to M.Columns do
write(M[row, col]:5:1);
writeln;
END;
writeln;
writeln('Перемещение');
for col := 1 to M.Columns do
BEGIN
for row := 1 to M.Rows do
write(M[row, col]:5:1);
writeln;
END;
M.Free;
END.
Очень простой пример...
Код Const
MaxBooleans = (High(Cardinal) - $F) div sizeof(boolean);
Type
TBoolArray = array[1..MaxBooleans] of boolean;
PBoolArray = ^TBoolArray;
Var
B : PBoolArray;
N : integer;
BEGIN
N := 63579;
{= получение памяти под динамический массив.. =}
GetMem(B, N*sizeof(boolean));
{= работа с массивом... =}
B^[3477] := FALSE;
{= возвращение памяти в кучу =}
{$IFDEF VER80}
FreeMem(B, N*sizeof(boolean));
{$ELSE}
FreeMem(B);
{$ENDIF}
END.
Данный модуль позволяет читать и записывать файлы формата Unix.
Код unit StreamFile;
interface
Uses
SysUtils;
Procedure AssignStreamFile (var F : Text ; Filename : String);
implementation
Const
BufferSize = 128;
Type
TStreamBuffer = Array [1..High (Integer)] of Char;
TStreamBufferPointer = ^TStreamBuffer;
TStreamFileRecord = Record
Case Integer Of
1:
(
Filehandle : Integer;
Buffer : TStreamBufferPointer;
BufferOffset : Integer;
ReadCount : Integer;
);
2:
(
Dummy : Array [1 .. 32] Of Char
)
End;
Function StreamFileOpen (var F : TTextRec) : Integer;
Var
Status : Integer;
Begin
With TStreamFileRecord (F.UserData) Do
Begin
GetMem (Buffer, BufferSize);
Case F.Mode Of
fmInput:
FileHandle := FileOpen (StrPas (F.Name), fmShareDenyNone);
fmOutput:
FileHandle := FileCreate (StrPas (F.Name));
fmInOut:
Begin
FileHandle := FileOpen (StrPas (F.Name), fmShareDenyNone Or
fmOpenWrite or fmOpenRead);
If FileHandle <> -1 Then
status := FileSeek (FileHandle, 0, 2); { Перемещаемся в конец файла. }
F.Mode := fmOutput;
End;
End;
BufferOffset := 0;
ReadCount := 0;
F.BufEnd := 0; { В этом месте подразумеваем что мы достигли конца файла (eof). }
If FileHandle = -1 Then
Result := -1
Else
Result := 0;
End;
End;
Function StreamFileInOut (var F : TTextRec) : Integer;
Procedure Read (var Data : TStreamFileRecord);
Procedure CopyData;
Begin
While (F.BufEnd < Sizeof (F.Buffer) - 2)
And (Data.BufferOffset <= Data.ReadCount)
And (Data.Buffer [Data.BufferOffset] <> #10) Do
Begin
F.Buffer [F.BufEnd] := Data.Buffer^ [Data.BufferOffset];
Inc (Data.BufferOffset);
Inc (F.BufEnd);
End;
If Data.Buffer [Data.BufferOffset] = #10 Then
Begin
F.Buffer [F.BufEnd] := #13;
Inc (F.BufEnd);
F.Buffer [F.BufEnd] := #10;
Inc (F.BufEnd);
Inc (Data.BufferOffset);
End;
End;
Begin
F.BufEnd := 0;
F.BufPos := 0;
F.Buffer := '';
Repeat
Begin
If (Data.ReadCount = 0) Or (Data.BufferOffset > Data.ReadCount) Then
Begin
Data.BufferOffset := 1;
Data.ReadCount := FileRead (Data.FileHandle, Data.Buffer^, BufferSize);
End;
CopyData;
End Until (Data.ReadCount = 0)
Or (F.BufEnd >= Sizeof (F.Buffer) - 2);
Result := 0;
End;
Procedure Write (var Data : TStreamFileRecord);
Var
Status : Integer;
Destination : Integer;
II : Integer;
Begin
With TStreamFileRecord (F.UserData) Do
Begin
Destination := 0;
For II := 0 To F.BufPos - 1 Do
Begin
If F.Buffer [II] <> #13 Then
Begin
Inc (Destination);
Buffer^[Destination] := F.Buffer [II];
End;
End;
Status := FileWrite (FileHandle, Buffer^, Destination);
F.BufPos := 0;
Result := 0;
End;
End;
Begin
Case F.Mode Of
fmInput:
Read (TStreamFileRecord (F.UserData));
fmOutput:
Write (TStreamFileRecord (F.UserData));
End;
End;
Function StreamFileFlush (var F : TTextRec) : Integer;
Begin
Result := 0;
End;
Function StreamFileClose (var F : TTextRec) : Integer;
Begin
With TStreamFileRecord (F.UserData) Do
Begin
FreeMem (Buffer);
FileClose (FileHandle);
End;
Result := 0;
End;
Procedure AssignStreamFile (var F : Text ; Filename : String);
Begin
With TTextRec (F) Do
Begin
Mode := fmClosed;
BufPtr := @Buffer;
BufSize := Sizeof (Buffer);
OpenFunc := @StreamFileOpen;
InOutFunc := @StreamFileInOut;
FlushFunc := @StreamFileFlush;
CloseFunc := @StreamFileClose;
StrPLCopy (Name, FileName, Sizeof(Name) - 1);
End;
End;
end.
Внимание! Если у вас не получилось найти нужную информацию, используйте
рубрикатор или воспользуйтесь
поиском .
книги по программированию исходники компоненты шаблоны сайтов C++ PHP Delphi скачать