1 (изменено: stealzy, 2015-12-23 06:43:50)

Тема: AHK: Продвинутый RegExReplace

Возникла тут задача синхронизировать по времени файл субтитров с видео.
Файл субтитров .srt оказался текстовым и содержал временные метки в формате hh:mm:ss и привязанные к ним реплики.
Для синхронизации нужно сдвинуть все метки на х минут у секунд.

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

filePath := "S:\kino\The Intern (2015).srt"
shift:=-62 ; sec

FileRead text, %filePath%
modText := RegExReplFunc(text, "\d\d:\d\d:\d\d", "timeShift", [shift])
FileMove %filePath%, %filePath%_orig
FileAppend %modText%, %filePath%
Return

RegExReplFunc(haystack, NeedleRegEx, f, p) {
	pos:=1
	NeedleRegEx:= "O)" NeedleRegEx

	while RegExMatch(haystack, NeedleRegEx, Match, pos) {
		matchWord:=Match.Value(0)
		postWord := %f%(matchWord, p*)
		if (postWord != false)
			haystack :=	RegExReplace(haystack, matchWord, postWord, byRefNumberOfRepl, limit:=1, pos)
		pos := Match.Pos(0) + Match.Len(0)
	}

	Return haystack
}

timeShift(time, shift) {
	; 23:30:55 + 100 = 23:32:35
	RegExMatch(time, "O)^\d\d", Match)
	hh := Match.Value(0)
	RegExMatch(time, "O)(?<=:)\d\d(?=:)", Match)
	mm := Match.Value(0)
	RegExMatch(time, "O)\d\d$", Match)
	ss := Match.Value(0)

	t = 19990101 ; дата от балды
	t += hh*3600 + mm*60 + ss, Seconds
	t += %shift%, Seconds
	FormatTime t, %t%, HH:mm:ss

	return t
}

Offtop: Конечно, должны существовать специально заточенные под работу с сабами программы, но было интересно решение в общем случае.

2

Re: AHK: Продвинутый RegExReplace

stealzy, работает! Только перемудрили немного, RegExReplace слишком уж продвинутый у вас получился.

text =
(
627
00:54:37,670 --> 00:54:39,300
- Идем со мною, Мойше.

628
00:54:48,770 --> 00:54:51,100
Делай всё, что скажет
этот хороший дядя.
)

MsgBox, % newText := TimeChange(text, -62)

TimeChange(text, shift)
{
	pos := 0
	while pos := RegExMatch(text, "\d\d:\d\d:\d\d", match, pos + 1)
		text := RegExReplace(text, match, ShiftTime(match, shift), "", 1, pos)
	Return text
}

ShiftTime(time, shift)
{
	ts := "16010102" . StrReplace(time, ":")
	ts += shift, Seconds
	FormatTime, newTime, % ts, HH:mm:ss
	Return newTime
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

3 (изменено: stealzy, 2015-12-24 15:34:50)

Re: AHK: Продвинутый RegExReplace

teadrinker, я это чувствовал, поэтому и выложил сюда ;-). Спасибо, что не подвели.
Со временем первый раз вожусь, поэтому так неказисто вышло.

Постарался оформить как библиотеку:


; regExReplFunc(haystack, NeedleRegEx, func, p)
; Замена в переменной <haystack> выражений, совпавших с шаблоном <NeedleRegEx> на результат, возвращенный функцией <func>, где
; func - имя ф-ии, p - массив, содержащий параметры для ф-ии.
; Чтобы передать в ф-ию <func> найденное совпадение и его позицию, используются зарезервированные параметры "_value" и "_pos".
; Если ф-ия <func> возвращает false, замена не производится.

; Пример использования - сдвиг времени в содержимом переменной text только в первых 25 символах содержимого, используя функцию timeShift.
; text ="12:03 - day, 19:27 - evening, 01:34 - night, 16:35"
; MsgBox % "haystack := " text "`n`nregExReplFunc(haystack, ""\d\d:\d\d"", ""timeShift"", [""_value"", ""_pos"", 5, 25])" "`n`nResult   := " regExReplFunc(text, "\d\d:\d\d", "timeShift", ["_value", "_pos", timeShift:=5, dontReplaceAfterSymbols:=25])
; Return
; timeShift(time, pos, shift, dontReplaceAfterSymbols) {
; 	ts := "19900102" . StrReplace(time, ":")
; 	ts += shift, Hours
; 	FormatTime, newTime, % ts, HH:mm
; 	if (pos > dontReplaceAfterSymbols)
; 		newTime:=false ; не заменять
; 	Return newTime
; }

regExReplFunc(haystack, NeedleRegEx, func, p) {
	; NeedleRegEx options change
		options:="^[imsxADJUXS]+\)", denyOptions:="^[imsxADJUXS]*P(?:[imsxADJUXS]*)\)"
		; Remove "P" from options
		if RegExMatch(NeedleRegEx,denyOptions,do)
			NeedleRegEx := RegExReplace(NeedleRegEx, denyOptions, RegExReplace(do,"P"))
		; Add "O" and "m" to options
		if RegExMatch(NeedleRegEx,options,o) {
			NeedleRegEx := RegExReplace(NeedleRegEx,options,(!InStr(o,"m") ? "m$0" : "$0"))
			NeedleRegEx := RegExReplace(NeedleRegEx,options,(!InStr(o,"O") ? "O$0" : "$0"))
		} else NeedleRegEx := "Om)" . NeedleRegEx
	
	pos:=1
	while regexmatch(haystack, NeedleRegEx, Match, pos)
	{
		; replace reserved words "_value", "_pos" in function parameters array to Match.0 and Match.Pos(0) content.
		pn:={}
		Loop % p.MaxIndex()
			pn[A_Index] := ((p[A_Index] = "_value") || (p[A_Index] = "_pos") ) ? p[A_Index](Match) : p[A_Index]
		; don't replace if function return false
		haystack :=	((replacement:=%func%(pn*)) != false) ? regexreplace(haystack, Match.0, replacement, byRefNumberOfRepl, limit:=1, pos) : haystack
		pos := Match.Pos(0) + Match.Len(0)
	}
	Return haystack
}
_value(Match) {
	Return % Match.0
}
_pos(Match) {
	Return % Match.Pos(0)
}