Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2005.06.14;
Скачать: CL | DM;

Вниз

Поиск по файлу   Найти похожие ветки 

 
lmz ©   (2005-05-23 20:17) [0]

Алгоритм поиска по файлу: например, есть какой то файл, в нём написан какой-то текст, необходимо найти некоторые слова и вывести результаты поиска?


 
злобная танька   (2005-05-23 20:21) [1]

копируй файл в переменную и шерсти его функцией Pos!


 
lmz ©   (2005-05-23 20:23) [2]

А если файл очень большой, тогда поиск может затянуться на несколько минут... может есть что оптимальное...


 
Yanis ©   (2005-05-23 20:26) [3]

Особенно прикольно когда файл размером около 1GB =)


 
DSKalugin ©   (2005-05-23 20:27) [4]

Поиск в TMemo с использованием TFindDialog
http://delphiworld.narod.ru/base/memo_search_dlg.html


 
злобная танька   (2005-05-23 20:36) [5]

здесь такая тема уже поднималась.. полазийте в архивах форума!
там развели эту тему на 170 страниц, и в итоге написали функцию, как раз как вам нада. Очень быструю.


 
Yanis ©   (2005-05-23 20:41) [6]


здесь такая тема уже поднималась.. полазийте в архивах форума!
там развели эту тему на 170 страниц, и в итоге написали функцию, как раз как вам нада. Очень быструю.

Да уж. Помню, помню =) Разве её теперь найдешь! Это надо у авторов спросить.


 
злобная танька   (2005-05-23 20:43) [7]

одного из авторов GuAV звали
напишите ему письмо :D


 
lmz ©   (2005-05-23 21:15) [8]

Может кто помнит как тема называлась. Как написать письмо этому GuAV?


 
злобная танька   (2005-05-23 21:20) [9]

поиск по анкетам слабо?
guav(сабака)mail.ru


 
Yanis ©   (2005-05-23 21:21) [10]

http://www.delphimaster.ru/cgi-bin/anketa.pl?id=1087039622


 
Yanis ©   (2005-05-23 21:21) [11]


> поиск по анкетам слабо?
> guav(сабака)mail.ru

Опередила =)


 
lmz ©   (2005-05-23 21:27) [12]

Попробую спросить...


 
Sha ©   (2005-05-23 22:02) [13]

GuAV & Defunct писали вдвоем.
Когда уставал один, эстафету подхватывал другой...
Так и не дописали :)


 
Yanis ©   (2005-05-23 22:04) [14]


GuAV & Defunct писали вдвоем.

Точно. Вроде они вдвоём =) Тут главное никого не забыть, а то код 2м писали, а его присвоили одному.


 
lmz ©   (2005-05-23 23:13) [15]

Так может у кого-то есть код... поделитесь...


 
GuAV ©   (2005-05-24 00:39) [16]

Код писал в основном Defunct (по крайней мере он был последним, я после переходе на mmx сдался :) ). Поскольку тот код содержал ошибку (выход из диапазона при чтении, маловероятно, но потенциально AV), не предсатвляет большой ценности.

Вот тут код, который так и не удалось обогнать:

http://dennishomepage.gugs-cats.dk/PosChallenge.htm - скачайте Validation and Benchmark Tool и сами выберите функцию-альтернативу Pos.

ещё советы:

Читайте файл сразу в строку, используя выделение памяти через SetLength.

Читайте не очень мелкими (чтобы уменьшить количество операций) но и не очень большими (чтобы избежать своппинга) блоками.

Также имеет смысл попробовать применить MMF, однако в этом прийдётся адаптировать ф-цию Pos под использования указателя на буфер и длины вместо строки.


 
Alx2 ©   (2005-05-24 00:47) [17]


procedure LoadFromFile(const FileName: string);
 procedure DoError;
 begin
   raise
     Exception.Create("TStorage.LoadFromFile(""" + FileName + """): " + SysErrorMessage(GetLastError));
 end;
var
 cfmHandle, hFile: THandle;
 DataAddress: Pointer;
 fSize: DWord;
begin
 hFile := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
 if hFile = invalid_handle_value then
   DoError
 else
 try
   fSize := GetFileSize(hFile, nil);
   if fSize = $FFFFFFFF then
     DoError else
   begin
     cfmHandle := CreateFileMapping(hFile, nil, PAGE_READONLY, 0, fSize, "");
     if cfmHandle = 0 then
       DoError
     else
     try
       DataAddress := MapViewOfFile(cfmHandle, FILE_MAP_READ, 0, 0, 0);
       if DataAddress = nil then
         DoError
       else
       try
         Здесь работаем с файлом, как с массивом.
Адрес массива в DataAddress.
"однако в этом прийдётся адаптировать ф-цию Pos под использования указателя на буфер и длины вместо строки." (с) GuAV ©   (24.05.05 00:39)

{
Как пример: содержимое файла запихнем в строку (зачем? - не знаю. Просто пример:)
         SetLength(Str, fSize);
         Move(DataAddress^, Str[1], fSize);

}
       finally
         UnmapViewOfFile(DataAddress);
       end;
     finally
       CloseHandle(cfmHandle);
     end;
   end;
 finally
   CloseHandle(hFile);
 end;
end;



PS
Только для файлов размером <2Gb


 
lmz ©   (2005-05-24 11:23) [18]

А можно полный работающий код


 
Игорь Шевченко ©   (2005-05-24 11:29) [19]

GuAV ©   (24.05.05 00:39) [16]


> Также имеет смысл попробовать применить MMF, однако в этом
> прийдётся адаптировать ф-цию Pos под использования указателя
> на буфер и длины вместо строки.


А кроме Pos науке поиска никакие методы, натурально, не известны.


 
Alx2 ©   (2005-05-24 11:35) [20]

>Игорь Шевченко ©   (24.05.05 11:29) [19]
Стоит перечислить все? :)


 
Sha ©   (2005-05-24 11:46) [21]

> lmz ©   (24.05.05 11:23) [18]
> А можно полный работающий код

Зачем код, можно сразу результат получить. (с) Google.


 
Defunct ©   (2005-05-24 14:07) [22]

lmz ©   (24.05.05 11:23) [18]

Функции специально адаптированные под поиск в файле:
(C) Def and GuAV
У кого осталась та ветка, это приведены функции [74] и [87]. (не самые быстрые, зато рабочие).

function ConstantPos(const Constant: string;
        Buffer: Pointer; BufSize: Integer): Integer; Assembler;
asm
 Push EDi
 Push ESi
 Push EBx
 Push EBp
 Push ECx            // store total buffer size for later calculation pos
 MOV  ESI, EAX       // ESi pointer to constant
 Mov  EDi, EDx       // EDi pointer to buffer
 Mov  EBX, [ESI-4]
 Dec  EBX
 Mov  Ah, [ESi+EBx]  // Store last char of the constant in AH
 Dec  EBx            // EBx - length of the constant w/o 1st and last chars
 Mov  Al, [ESi]      // Store first char of the constant in AL
 Mov  EDx,ECx        // EDx - Stored residual buffer size
 Inc  ESi
 Mov  EBp, ESi       // EBp - stored pointer to 2nd char of constant

@@Scan:
 Repne ScasB
 JNE   @@Exit_False  // no 1st char of the constant found = exit_false
 Mov   EDx, ECx      // store new residual buffer size
 Cmp   EDx, EBx      // constant still can be settled in buffer
 Ja    @@CheckLastChar  // no - exit with false result

@@Exit_False:
 Pop  EAx
 Xor  EAx,EAx        // False = (0), check delphi help for more info
 Dec  EAx
 Jmp  @@Leave_Proc

@@CheckLastChar:      // as proposed in Boyer-Mur alhorithm

 Cmp   Ah, [EDi+EBx] // check found substring with last char of the constant
 Jnz   @@Scan        // not match - continue searching

@@CompareWholeString:
 Mov  ECx, Ebx       // ECx - constant chars amount
 Repe CmpsB
 Jz   @@Constant_Exists
 Mov  ESi, EBp       // restore pointer to 2nd char of constant
 Add  EDx, ECx
 Sub  EDx, EBx       // correct residual buffer size
 Mov  ECx, EDx       // restore residual buffer size to ECx

 Jnz  @@Scan

@@Constant_Exists:
 Pop  EAx
 Sub  EAx, EDx

@@Leave_Proc:

 Pop  EBp
 Pop  EBx
 Pop  ESi
 Pop  EDi
end;

function ConstantExists(FileName, Constant: String): Int64;
const
   MaxBufferSize = 1024*1024;
type
   TBuffer = array[0..MaxBufferSize-1] of byte;
   PBuffer = ^TBuffer;

var
   Buffer  : PBuffer;
   F       : File;
   BufSize : Integer;
   BufPos  : Integer;
begin
  BufPos := -1;
  New(Buffer);
  try
     AssignFile(F, FileName);
     Reset(F,1);
     try
        repeat
           Result := FilePos(F);
           BlockRead(F, Buffer^, MaxBufferSize, BufSize);
           If BufSize >= Length(Constant) Then
              BufPos := ConstantPos(Constant, Buffer, BufSize);
           Result := Result + BufPos;
           Seek(F, FilePos(F) - Length(Constant));
        until (BufPos>0) or (BufSize<MaxBufferSize);
     finally
       CloseFile(F)
     end
  finally
     Dispose(Buffer);
  end
end;


Пример использования:

procedure TForm1.Button1Click(Sender: TObject);
var APos : Int64;
begin
 APos := ConstantExists("E:\Films\SMovie.avi", "JUNKV");
 if APos <> -1 then
    ShowMessage("JUNKV at "+IntToStr(APos) );
end;


 
Defunct ©   (2005-05-24 14:20) [23]

Прощу прощения..  В оригинале было так:


    finally
      CloseFile(F)
    end;
    if BufPos < 0 Then Result := -1;  
 finally
    Dispose(Buffer)
 end
end;


 
lmz ©   (2005-05-24 14:52) [24]

Не то получается, наример есть какая-то база, возьмём телефоный справочник, в этом файле записаны фамилии, номера, адреса, мне надо, чтобы при вводе какой-то фамилии выводились все похожие?


 
Viktop   (2005-05-24 14:54) [25]

А здесь что не так?


 
lmz ©   (2005-05-24 14:59) [26]

Во всяком случае, у меня получилось не так, тут число получается...


 
Viktop   (2005-05-24 15:05) [27]

Посмотреть бы на эти [74] и [87]


 
Игорь Шевченко ©   (2005-05-24 15:14) [28]


> Не то получается


Надеюсь, ты уже исправил данный тебе (даром!) код, так, чтобы он работал в соответствии с твоими требованиями ?


 
lmz ©   (2005-05-24 15:17) [29]


> уже исправил

Не  исправил...


 
lmz ©   (2005-05-24 15:22) [30]


> function ConstantPos(const Constant: string;
>         Buffer: Pointer; BufSize: Integer): Integer; Assembler;
> asm
>  Push EDi
>  Push ESi
>  Push EBx
>  Push EBp
>  Push ECx            // store total buffer size for later
> calculation pos
>  MOV  ESI, EAX       // ESi pointer to constant
>  Mov  EDi, EDx       // EDi pointer to buffer
>  Mov  EBX, [ESI-4]
>  Dec  EBX
>  Mov  Ah, [ESi+EBx]  // Store last char of the constant
> in AH
>  Dec  EBx            // EBx - length of the constant w/o
> 1st and last chars
>  Mov  Al, [ESi]      // Store first char of the constant
> in AL
>  Mov  EDx,ECx        // EDx - Stored residual buffer size
>  Inc  ESi
>  Mov  EBp, ESi       // EBp - stored pointer to 2nd char
> of constant
>
> @@Scan:
>  Repne ScasB
>  JNE   @@Exit_False  // no 1st char of the constant found
> = exit_false
>  Mov   EDx, ECx      // store new residual buffer size
>  Cmp   EDx, EBx      // constant still can be settled in
> buffer
>  Ja    @@CheckLastChar  // no - exit with false result
>
> @@Exit_False:
>  Pop  EAx
>  Xor  EAx,EAx        // False = (0), check delphi help for
> more info
>  Dec  EAx
>  Jmp  @@Leave_Proc
>
> @@CheckLastChar:      // as proposed in Boyer-Mur alhorithm
>
>  Cmp   Ah, [EDi+EBx] // check found substring with last
> char of the constant
>  Jnz   @@Scan        // not match - continue searching
>
> @@CompareWholeString:
>  Mov  ECx, Ebx       // ECx - constant chars amount
>  Repe CmpsB
>  Jz   @@Constant_Exists
>  Mov  ESi, EBp       // restore pointer to 2nd char of constant
>  Add  EDx, ECx
>  Sub  EDx, EBx       // correct residual buffer size
>  Mov  ECx, EDx       // restore residual buffer size to
> ECx
>
>  Jnz  @@Scan
>
> @@Constant_Exists:
>  Pop  EAx
>  Sub  EAx, EDx
>
> @@Leave_Proc:
>
>  Pop  EBp
>  Pop  EBx
>  Pop  ESi
>  Pop  EDi
> end;


Как использовать эту функцию? Что передавать в параметры Buffer и BufSize?


 
Viktop   (2005-05-24 16:01) [31]

Как-то странно работаю эти функции :(. Сначала выдавала на 1 найденый элемент больше. Потом стала выдавать числа за 1000, хотя в файле 100 слов максимум. Далее: В файл поместил 5 одинаковых строк - число найденных = 1


 
lmz ©   (2005-05-24 16:15) [32]

Вот и я про тоже...


 
nikkie ©   (2005-05-24 16:28) [33]

чужой код - он такой. никогда не работает, как надо.


 
Alx2 ©   (2005-05-24 16:30) [34]

>lmz ©   (24.05.05 16:15)

Сам в массиве можешь заданную цепочку найти?


 
ANB ©   (2005-05-24 16:38) [35]


> Не то получается, наример есть какая-то база, возьмём телефоный
> справочник, в этом файле записаны фамилии,
- имхо, ты хочешь движок БД написать ? Опять таки, имхо, проще тогда готвую СУБД использовать. В них есть поиск по индексу. А поиск перебором в файле 1Г по любому медленно работать будет.


 
Viktop   (2005-05-24 16:52) [36]

to nikkie
А ты попробуй скорми этим функция файл с парой строк и поэксперементируй. Я бы потправил, но знания asma=0,00001% (знаю что что-то там про регистры есть)


 
Defunct ©   (2005-05-24 17:07) [37]

lmz ©   (24.05.05 15:22) [30]

Вам не нужно использовать непосредственно ASM функцию. Вам достаточно использовать как в примере, функцию ConstantExists, которая возвращает позицию искомой константы в файле.


 
Viktop   (2005-05-24 17:09) [38]

to Defunct
А глюки с поиском Вы не замечали (кол-во найденного)?


 
Defunct ©   (2005-05-24 17:16) [39]

Viktop   (24.05.05 17:09) [38]

> А глюки с поиском

Подробнее про глюки плз. т.к. не замечал глюков именнов в этих функциях.


 
lmz ©   (2005-05-24 18:07) [40]


> в файле 1Г

Почему 1Г, размер файла может быть от 2 метров до 50 метров...


 
Viktop   (2005-05-24 20:23) [41]

to Defunct
Пост 31

P.S.: Я, кажется простое решение нашёл:
function InStr(index: integer; str1: string; str2: string): integer;
var
 i,len, pos: integer;
begin
 pos:=0;
 len:=length(str2);
 for i:=index to length(str1) do begin
   if copy(str1,i,len)=str2 then begin
     pos:=i;
     break; // здесь можно писать свои условия
   end;
 end;
 result:=pos;
end;


Параметры функции:
номер символа, с которго ищем, в какой строке ищем, что ищем


 
Defunct ©   (2005-05-24 20:55) [42]

Viktop   (24.05.05 20:23) [41]

Функция ищет не количество подстрок, а позицию подстроки в файле. При этом в отличие от Pos поиск не приостанавливается на служебных символах #0 и т.п. Изначально функция [22] была предназначена для поиска подстрок в бинарном файле.


 
Viktop   (2005-05-25 04:50) [43]

Ну ведь можно добавить:
For i:=index to length(str1) do begin
  if copy(str1,i,len)=str2 then begin
    pos:=i;
    Inc(numder)
  end;

А зачем поиск должен приостанавливаться?



Страницы: 1 2 вся ветка

Текущий архив: 2005.06.14;
Скачать: CL | DM;

Наверх




Память: 0.59 MB
Время: 0.031 c
9-1106580715
Trof
2005-01-24 18:31
2005.06.14
Ландшафт в 3dsmax.


11-1098792092
Loader
2004-10-26 16:01
2005.06.14
Обработка сообщений в сетевом приложении на KOL


1-1117001110
Kolan
2005-05-25 10:05
2005.06.14
Как экспортировать класс из dll.


14-1116796669
Zacho
2005-05-23 01:17
2005.06.14
AMD: Три буквы для бедных


6-1111736034
Илья
2005-03-25 10:33
2005.06.14
Передача файлов по сети