Что нового

[Данные, строки] Как ускорить работу StringInStr ?

zero_1632

Новичок
Сообщения
15
Репутация
0
Возникал задача искать некоторые слова в локальных файлах на диске. Более того, учитывать их количество. Для одного большого файла (2-3 мб) поиск слов с помощью StringInStr (словарь из слов, которые надо искать, около 40) скорость обработки фала 150 кбайт/c. Нельзя ли как-то убыстрить этот процесс?

Ну и в связи с первым вопросом проблема чтения больших файлов - при FileRead периодически выскакивает Error allocation Memory. При этом файлы-то небольшие, порядка 40 Мбайт. Пришлось делать FileRead ($file,10000). Что0нибудь можно сделать, чтобы запихивать в память весь файл? Файлы как ASCII так и бинарные.
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
zero_1632 [?]
Нельзя ли как-то убыстрить этот процесс?
Можно, если вы покажете этот “процесс” ;)

при FileRead периодически выскакивает Error allocation Memory
Сразу видно что поиск производится неправильно.

Что0нибудь можно сделать, чтобы запихивать в память весь файл?
Нет, в AutoIt есть ограничения. Но для 40 mb должно хватить (при граммотном считываний).
 
Автор
Z

zero_1632

Новичок
Сообщения
15
Репутация
0
Можно, если вы покажете этот “процесс”

Пожалуйста - вот кусок кода.
$block_size_read_files_in_chars равен как раз около 32 Мбайт
$dict_otbor_array - собственно те слова, которые надо искать, загнанные из файла в массив


Код:
While 1

		$temp1 = FileRead($file_open, $block_size_read_files_in_chars)
		If @error Then ExitLoop
		
		For $i = 1 To $dict_otbor_array[0]
		If StringInStr($temp1, $dict_otbor_array[$i], 2) > 0 Then
		FileClose($file_open)
		FileMove($current_file_full_path, $out_directory, 9)
		ExitLoop 2
		EndIf
		Next

WEnd

Только ускорять там нечего. Может быть имеет смысл просто добавлять файл с использованием sqlite и там уже искать? Как раз с использованием временной базы в памяти? Файлов много,

Сразу видно что поиск производится неправильно.

Уфф. А что делать?
 

asdf8

Скриптер
Сообщения
564
Репутация
152
Саму функцию StringInStr можно ускорить на ~30%, указав casesense=0.
Но это мало что изменит, потому-что в приведенной функции большая часть
времени уходит на чтение и перемещение файлов.
 
Автор
Z

zero_1632

Новичок
Сообщения
15
Репутация
0
большая часть
времени уходит на чтение и перемещение файлов.

хорошо, а как ЭТО ускорить? допустим что даже можно запускать отдельный внешний exe-шник, передавая ему параметром откуда копировать и куда. Как ускорить чтение файла?
Можно ли использовать sqlite для внесения в таблицу в памяти этого файла (сразу снимутся все проблемы с ограничением чтения в 40 мб) и ускорит ли это работу?
 

asdf8

Скриптер
Сообщения
564
Репутация
152
[?]
Цитата сказал(а):
большая часть времени уходит на чтение и перемещение файлов.
это я имел в виду для файлов 2-3Мб, для файлов ~50Мб, поиск по файлу займет гораздо больше времени.
Ускорить перемещение файлов можно попробовать отключив антивирус, а поиск - используя регекспы:

Код:
$sFind = ''
For $i = 1 To $dict_otbor_array[0]
	$sFind &= StringRegExpReplace($dict_otbor_array[$i], '(\^|\.|\(|\)|\[|\]|\+|\$|\*|\\|\|)', '\\\1') & '|'
Next
$sFind = '(' & StringTrimRight($sFind, 1) & ')'

....

$str=FileRead($current_file_full_path)
If StringInStr($str, Chr(0)) Then $str=StringReplace($str, Chr(0), Chr(1));для бинарных файлов
If StringRegExp($str, $sFind) Then FileMove($current_file_full_path, $out_directory, 9)


пробывал этот код на файлах 50Мб, общая скорость обработки на моем компе получилась ~1,3Мб/сек
 
Автор
Z

zero_1632

Новичок
Сообщения
15
Репутация
0
Снимаю шляпу. Эта идея мне как-то в голову не приходила.
Должно быть быстрее - буду пробовать.

не очень понял, что такое \\\1 в
Код:
$sFind &= StringRegExpReplace($dict_otbor_array[$i], '(\^|\.|\(|\)|\[|\]|\+|\$|\*|\\|\|)', '\\\1')


Можно где-то кроме хелпа и ведущего в интернет http://www.autoitscript.com/autoit3/pcrepattern.html (там как-то тоже ясно не нашел)

И зачем эта замена?
Код:
($str, Chr(0), Chr(1))
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
zero_1632 [?]
Это замена на слеш и на первую группу (то что в начальных скобках), т.е ко всему найденному, будет добавлен слеш в начало.

asdf8 [?]
поиск - используя регекспы
Тут я думаю оно будет уступать, разве что если использовать одним махом (без цикла).

zero_1632
Откуда берётся массив «$dict_otbor_array»? я так полагаю есть исходная строка?
 

asdf8

Скриптер
Сообщения
564
Репутация
152
[?]
Цитата сказал(а):
это, чтобы экранировать спецсимволы, т.е. чтоб регэкспы искали по правилам StringInStr.

[?]
Цитата сказал(а):
Файлы как ASCII так и бинарные.
если не заменить Chr(0) на Chr(1) регэкспы будут искать только до первого Chr(0), т.е. строка обрежется.

[?]
Цитата сказал(а):
разве что если использовать одним махом (без цикла).
похоже, что циклы в AutoIt медленнее
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
asdf8 [?]
это, чтобы экранировать спецсимволы
а зачем столько групп?
Код:
$sFind &= StringRegExpReplace($dict_otbor_array[$i], '([\Q\.+*?^$[](){}|\E])', '\\\1')


и вообще в этом случае можно сразу их отменять:
Код:
$sFind = ''
For $i = 1 To $dict_otbor_array[0]
    $sFind &= $dict_otbor_array[$i] & '|'
Next
$sFind = '(\Q' & StringTrimRight($sFind, 1) & '\E)'

...
 

asdf8

Скриптер
Сообщения
564
Репутация
152
[?]
Цитата сказал(а):
а зачем столько групп?
Код: AutoIt [Выделить]
$sFind &= StringRegExpReplace($dict_otbor_array[$i], '([\Q\.+*?^$[](){}|\E])', '\\\1')

да - так лучше, хотя, в данном случае, это на скорость не влияет.

И еще из этого выражения надо убрать {} - в автоитовских регэкспах это не спецсимволы - будет искать неправильно.
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
asdf8 [?]
из этого выражения надо убрать {} - в автоитовских регэкспах это не спецсимволы
При заменен как раз таки да, но в Pattern действительно оно не нужно.

будет искать неправильно
Это почему?

Код:
$vTest = 'This {is} a Test'
$sRet = StringRegExpReplace($vTest, '(\{(is)\})', '\2')
ConsoleWrite($sRet & @LF)
 

asdf8

Скриптер
Сообщения
564
Репутация
152
Да - похоже регэкспам по барабану - стоит "\" перед фигурными скобками, или нет.
Похоже, это единственный случай в этом роде.
 
Автор
Z

zero_1632

Новичок
Сообщения
15
Репутация
0
Откуда берётся массив «$dict_otbor_array»? я так полагаю есть исходная строка?


Да просто читается из ini файла, делаю я его для поиска по весу интересующих слов в файле.
вроде
Код:
sale=10
mail.ru=-20
spam=-1000

Для чтения используется функция _IniReadSectionEx.


При
Код:
$sFind = ''
For $i = 1 To $dict_otbor_array[0]
    $sFind &= $dict_otbor_array[$i] & '|'
Next
$sFind = '(\Q' & StringTrimRight($sFind, 1) & '\E)'


Я так понял, символы или - "|" работать не будут?

У меня получилось чуть подправить:

Код:
$sFind = ''
For $i = 1 To $dict_otbor_array[0]
    $sFind &= "\Q" & $dict_otbor_array[$i] & "\E" & '|'
Next
$sFind = '(?i:' & StringTrimRight($sFind, 1) & ')'
ConsoleWrite ($sFind & @CR)
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Верх