Что нового

[Баг] Утечка памяти при использовании RegExp

Heler

Знающий
Сообщения
70
Репутация
11
Всем привет! Знакомый попросил подкоректировать время в файле субтитров. После чего на скорую руку был написан скрипт. При выполнении начинает кушать много памяти и примерно через 40 секунд вылетает с ошибкой "Error allocating memory". Файл субтитров для обработки в аттаче.
Код:
$sFile = @ScriptDir&"DragonBall.txt"
$sReadFile = FileRead ($sFile)
$sOrigString = StringRegExp($sReadFile, '(?m)^\d{1,4}\r\n\d{2}:\d{2}:\d{2}\,.*', 3)

For $i = 0 To Ubound($sOrigString)-1
	Local $sModString = $sOrigString[$i]
	$bTimeParts = StringRegExp($sOrigString[$i], '\d{2}:\d{2}:\d{2}', 3)
	$sModString = StringRegExpReplace($sModString, $bTimeParts[0],_SecAdd($bTimeParts[0],120))
	$sModString = StringRegExpReplace($sModString, $bTimeParts[1],_SecAdd($bTimeParts[1],120))
	$sReadFile  = StringRegExpReplace($sReadFile, $sOrigString, $sModString )
Next
FileWrite (@ScriptDir&"DragonBall.Mod.txt",$sReadFile)

Func _SecAdd($tTime,$tSec)
	$iTimeParts = StringSplit($tTime, ":")
	$iTicks = ((3600 * $iTimeParts[1]) + (60 * $iTimeParts[2]) + $iTimeParts[3])
	$iTicks += $tSec
	$iHours = StringFormat("%02d", Int($iTicks / 3600) )
	$iTicks = Mod($iTicks, 3600)
	$iMins = StringFormat("%02d", Int($iTicks / 60) )
	$iSecs = StringFormat("%02d", Mod($iTicks, 60) )
	Return $iHours&":"&$iMins&":"&$iSecs
EndFunc

AutoIT 3.3.6.1 OS:WIN_7 CPU:X64 OS:X64
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
626
Re: [Баг] Утечка памяти.

мде.. применять регэксп к такому большому файлу целиком? обрабатывай построчно и будет тебе счастье. возможно я ошибаюсь но мой диагноз - все дело в движке PCRE он просто с ума сходит от такого кол-ва строк. если я прав, то
1. это не баг
2. это не утечка. я посмотрел сколько используется памяти при выполнении скрипта. при утечке память циклически растет, пока не израсходует всю память. а тут это число скачает как в меньшую так и большую сторону. что означает что это как раз столько памяти требуется процессу. просто оно очень большое, в силу, как я уже сказал, большого числа строк
 
Автор
H

Heler

Знающий
Сообщения
70
Репутация
11
Re: [Баг] Утечка памяти.

мде.. применять регэксп к такому большому файлу целиком?
Всегда применял регэксп к большим файлам и отрабатывало почти моментально. Допустим я парсю html страницу. Мне нужно вытаскивать 2+ значения, которые находятся в разных строках, одним регэкспом. Тут вариант обрабатывать построчно не подойдет.

возможно я ошибаюсь но мой диагноз - все дело в движке PCRE он просто с ума сходит от такого кол-ва строк.
Если поставить MsgBox после строки:
Код:
$sReadFile  = StringRegExpReplace($sReadFile, $sOrigString, $sModString )

то можна увидеть, что первые 2 прохода выполняются моментально. Третий с задержкой в 1 секунду. А последующие еще дольше.
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
626
Re: [Баг] Утечка памяти.

Heler
ок. тогда пройдемся по твоему регвыру.
1. в последней замене твой шаблон - массив, что не есть хорошо.
2. если же поставить индекс, то получится шаблон - строка. НО! - шаблон не должен содержать пробелы и иные спец. символы которые могут встретиться в оригинальной строке, которая подлежт замене.
3. посему, если сделать вот так
Код:
$sReadFile  = StringReplace($sReadFile, $sOrigString[$i], $sModString )
вместо
Код:
$sReadFile  = StringRegExpReplace($sReadFile, $sOrigString, $sModString )

то у меня отработало нормально.
вобщем, не знаю что ты и как делал раньше, но повторюсь, что ты потеряешь колоссальное преимущество использования регулярных выражений при использовании длинных шаблонов. всегда можно сделать шаблон короче, но несколько, ну и т.д.

Код:
$sFile = @ScriptDir&"\DragonBall.txt"
$sReadFile = FileRead ($sFile)
$sOrigString = StringRegExp($sReadFile, '(?m)^\d{1,4}\r\n\d{2}:\d{2}:\d{2}\,.*', 3)

For $i = 0 To Ubound($sOrigString)-1
    Local $sModString = $sOrigString[$i]
    $bTimeParts = StringRegExp($sOrigString[$i], '\d{2}:\d{2}:\d{2}', 3)
    $sModString = StringRegExpReplace($sModString, $bTimeParts[0],_SecAdd($bTimeParts[0],120))
    $sModString = StringRegExpReplace($sModString, $bTimeParts[1],_SecAdd($bTimeParts[1],120))
    $sReadFile  = StringReplace($sReadFile, $sOrigString[$i], $sModString )
Next
FileWrite (@ScriptDir&"\DragonBall.Mod.txt",$sReadFile)

Func _SecAdd($tTime,$tSec)
    $iTimeParts = StringSplit($tTime, ":")
    $iTicks = ((3600 * $iTimeParts[1]) + (60 * $iTimeParts[2]) + $iTimeParts[3])
    $iTicks += $tSec
    $iHours = StringFormat("%02d", Int($iTicks / 3600) )
    $iTicks = Mod($iTicks, 3600)
    $iMins = StringFormat("%02d", Int($iTicks / 60) )
    $iSecs = StringFormat("%02d", Mod($iTicks, 60) )
    Return $iHours&":"&$iMins&":"&$iSecs
EndFunc

Func LineNo($i, $line = @ScriptLineNumber)
    ConsoleWrite($i & @TAB & $line & @CRLF)
EndFunc

PS: в твоем коде переменные с путями для файлов неверные.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Re: [Баг] Утечка памяти.

Это не баг, это невнимательность + неправильное название переменных ($sOrigString), что в свою очередь ввело в забдуждение... Кроме того,

[quote author=AutoIt Help]Caution: bad regular expressions can produce a quasi-infinite loop hogging the CPU, and can even cause a crash.[/quote]
 
Автор
H

Heler

Знающий
Сообщения
70
Репутация
11
Re: [Баг] Утечка памяти.

Спасибо большое ребята. В следующий раз буду внимательнее.
 
Верх