Поиск в тексте с использованием потока

Добрый день.Делфи изучать только начинаю, поэтому прошу не пинать за кривость кода и алгоритма.Задача стоит такая: есть много (около 1000) текстовых (xml) файлов. В каждом файле достаточно много раз (также около 1000) встречаются открывающийся тег и закрывающийся к нему. Между ними, собственно, сам номер. Необходимо перебрать все файлы в папке и вычленить из них списком все номера. Написал нижепреведенный код, но возникли несколько проблем: 1.Программа ищет только в первом файле из списка, дальше не идет. 2.Криво работает поток, по завершении работы программы, при закрытии крестиком падает в Access Violation. Вероятно можно было бы сделать без потока, но все зависает. В общем, прошу подсказать, как можно оптимизировать алгоритм.
procedure TMyThread.Execute;
var i : integer;
 nomer : string;
 cadnum1, cadnum2, c: integer;
begin
 c:= 0;
 for i := 0 to Form1.FileListBox1.Items.Count - 1 do
 begin
 Form1.Memo1.Lines.LoadFromFile(Form1.FileListBox1.Items[i]);
 stroka := Form1.Memo1.Text;
 while Pos('<CadastralNumber>', stroka) <> 0 do
 begin
 cadnum1 := Pos('<CadastralNumber>', stroka);
 cadnum2 := Pos('</CadastralNumber>', stroka);
 nomer := Copy(stroka,cadnum1+17, cadnum2-cadnum1-17);
 Form1.Memo2.Lines.Add(nomer);
 Delete(stroka,cadnum1,Length(nomer)+35);
 inc(c);
 Form1.Button1.Caption := inttostr(c);
 end;
 Form1.Memo2.Lines.SaveToFile('list.txt');

 end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var i : integer;
begin
 Thread := TMyThread.Create(false);
 Thread.Priority := tpNormal;
 Thread.FreeOnTerminate := True;

end;
5 ответов

1. Никогда, вообще никогда, никогда и ещё раз никогда не обращаться к форме или на форму из потока, без синхронизации. 2. Поток сам себя не уничтожит без FreeOnTerminate 3. Можно и без программирования, с помощью Notepad++ и регулярных выражений за минуту перебрать все файлы.4. Запустить несколько потоков, выдав им уникальную пачку файловиз общем массы.


1. Никогда, вообще никогда, никогда и ещё раз никогда не обращаться к форме или на форму из потока, без синхронизации. 2. Поток сам себя не уничтожит без FreeOnTerminate 3. Можно и без программирования, с помощью Notepad++ и регулярных выражений за минуту перебрать все файлы.4. Запустить несколько потоков, выдав им уникальную пачку файловиз общем массы.
1.Понятно, исправлюсь. 2.Так вроде прописано это у меня... Или неправильно написал? 3.Знать бы еще как это все написать там. 4.Ясно, тоже попробую.


исключить операцию модификации строк (Delete) и возможно (если скорость будет приемлима) отказаться от потоков для этого при поиске использовать PosEx (есть начиная с Delphi7)
cadnum1 := PosEx('<CadastralNumber>', stroka, cadmin1+...);
cadnum2 := PosEx('</CadastralNumber>', stroka, cadmin1);
не повторять поиск без небходимости, а шире пользоваться результатами
stroka := Form1.Memo1.Text;
 cadmin2:=1;
 while <u>cadmin2>0</u> do
 begin
 cadmin1:=posex('<CadastralNumber>', stroka, cadmin2);
 <u>if cadmin1>0</u> then cadnum2 := PosEx('</CadastralNumber>', stroka, cadmin1+...) else cadmin2:=-1;
 <u> if cadmin2>0 </u>then begin
 nomer := Copy(stroka,cadnum1+17, cadnum2-cadnum1-17);
 Form1.Memo2.Lines.Add(nomer);
 <u>// Delete(stroka,cadnum1,Length(nomer)+35);</u>
 inc(c);
 Form1.Button1.Caption := inttostr(c);
 end;
 end;
не использовать для накопления результатов визуальные компоненты (Tmemo) а использовать TStringList
mylist:=TstringList.Create;
 
 mylist.add(...);
 
 mylist.SaveTofile(...);
 
mylist.Free;
при использовании потоков узким местом будет встраивание КАЖДОГО результата поиска в общую базу. (добавление строки к общему списку). БЕЗ синхронизации нельзя, а при синхронизации (в предложенном изначально алгоритме) скорее всего потоки большую часть времени будут тратить на ожидание записи.использовать возможности стандартного для Windows парсера xml будет ли быстрее? не знаю, но удобнее для модификаций. правда потребует ознакомления с правилами и возможностями XML.
use msxml; //подключить стандартный для windows 

var
 doc: IXMLDOMDocument;
 list: IXMLDOMNodeList;
 xml: IXMLDOMNode;
 
doc:=CoDOMDocument.Create; 
doc.Load('1.xml'); //загрузить документ

list:=doc.selectnodes('//CadastralNumber'); //получить ВСЕ nodes данного тега.
for j:=0 to list.length-1 do begin 
 memox.add(list.items[j].text); //перенести значения каждого найденного тега в Мемо.
end;


присоединяюсь ко всему вышесказанному (имхо, особенно полезен для TC пост evg_m)!N@PsteR, не знаю, кто и зачем Вас заманил использованием потоков, но это явно не так задача, где использование потоков даст Вам выигрыш.Используйте обычный код + замените Memo на TStringList + откажитесь от Delete и этого будет достаточно, чтобы вашу тысячу файлов обработать за несколько секунд! Впрочем, об этом уже выше всё сказано.


использовать возможности стандартного для Windows парсера xml будет ли быстрее? не знаю, но удобнее для модификаций. правда потребует ознакомления с правилами и возможностями XML.
use msxml; //подключить стандартный для windows 

var
 doc: IXMLDOMDocument;
 list: IXMLDOMNodeList;
 xml: IXMLDOMNode;
 
doc:=CoDOMDocument.Create; 
doc.Load('1.xml'); //загрузить документ

list:=doc.selectnodes('//CadastralNumber'); //получить ВСЕ nodes данного тега.
for j:=0 to list.length-1 do begin 
 memox.add(list.items[j].text); //перенести значения каждого найденного тега в Мемо.
end;
Сделал вот так. Огромное Вам спасибо. Работает достаточно шустро. В секунду выделяет порядка 1000 записей.