Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 25.09.2013, 13:57   #1
N@PsteR
Новичок
Джуниор
 
Регистрация: 25.09.2013
Сообщений: 3
Вопрос Поиск в тексте с использованием потока

Добрый день.

Делфи изучать только начинаю, поэтому прошу не пинать за кривость кода и алгоритма.

Задача стоит такая: есть много (около 1000) текстовых (xml) файлов. В каждом файле достаточно много раз (также около 1000) встречаются открывающийся тег <CadastralNumber> и закрывающийся к нему. Между ними, собственно, сам номер. Необходимо перебрать все файлы в папке и вычленить из них списком все номера.

Написал нижепреведенный код, но возникли несколько проблем:
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;

Последний раз редактировалось N@PsteR; 25.09.2013 в 14:01.
N@PsteR вне форума Ответить с цитированием
Старый 25.09.2013, 14:16   #2
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,426
По умолчанию

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

4. Запустить несколько потоков, выдав им уникальную пачку файловиз общем массы.
Человек_Борща вне форума Ответить с цитированием
Старый 25.09.2013, 14:34   #3
N@PsteR
Новичок
Джуниор
 
Регистрация: 25.09.2013
Сообщений: 3
По умолчанию

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

4. Запустить несколько потоков, выдав им уникальную пачку файловиз общем массы.
1.Понятно, исправлюсь.
2.Так вроде прописано это у меня... Или неправильно написал?
3.Знать бы еще как это все написать там.
4.Ясно, тоже попробую.
N@PsteR вне форума Ответить с цитированием
Старый 25.09.2013, 14:38   #4
evg_m
Старожил
 
Регистрация: 20.04.2008
Сообщений: 5,527
По умолчанию

исключить операцию модификации строк (Delete) и возможно (если скорость будет приемлима) отказаться от потоков
для этого при поиске использовать PosEx (есть начиная с Delphi7)
Код:
cadnum1 := PosEx('<CadastralNumber>', stroka, cadmin1+...);
cadnum2 := PosEx('</CadastralNumber>', stroka, cadmin1);
не повторять поиск без небходимости, а шире пользоваться результатами
Код:
      stroka := Form1.Memo1.Text;
      cadmin2:=1;
      while cadmin2>0 do
      begin
        cadmin1:=posex('<CadastralNumber>', stroka, cadmin2);
        if cadmin1>0 then cadnum2 := PosEx('</CadastralNumber>', stroka, cadmin1+...) else cadmin2:=-1;
        if cadmin2>0 then begin
          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;
      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;
программа — запись алгоритма на языке понятном транслятору

Последний раз редактировалось evg_m; 25.09.2013 в 15:08.
evg_m вне форума Ответить с цитированием
Старый 25.09.2013, 15:21   #5
Serge_Bliznykov
Старожил
 
Регистрация: 09.01.2008
Сообщений: 26,229
По умолчанию

присоединяюсь ко всему вышесказанному (имхо, особенно полезен для TC пост evg_m)!

N@PsteR, не знаю, кто и зачем Вас заманил использованием потоков, но это явно не так задача, где использование потоков даст Вам выигрыш.

Используйте обычный код + замените Memo на TStringList + откажитесь от Delete
и этого будет достаточно, чтобы вашу тысячу файлов обработать за несколько секунд!
Впрочем, об этом уже выше всё сказано.
Serge_Bliznykov вне форума Ответить с цитированием
Старый 25.09.2013, 15:48   #6
N@PsteR
Новичок
Джуниор
 
Регистрация: 25.09.2013
Сообщений: 3
По умолчанию

Цитата:
Сообщение от evg_m Посмотреть сообщение

использовать возможности стандартного для 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 записей.

Последний раз редактировалось N@PsteR; 25.09.2013 в 15:52.
N@PsteR вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Поиск в тексте Terikon Общие вопросы Delphi 2 06.05.2011 23:01
Передача потока с использованием idtcpServer Lvenok Помощь студентам 0 24.03.2010 19:03
Поиск в тексте Whiter Общие вопросы Delphi 10 30.07.2009 15:55
Поиск в тексте Rigard Общие вопросы Delphi 8 15.10.2008 00:06
Поиск в тексте jone Общие вопросы Delphi 14 28.09.2008 12:42