正则调出提供了一种在正则表达式模式匹配过程中临时将控制权传递给脚本的方法. 关于 PCRE 标准调出功能的详细信息, 请参阅 pcre.txt.
目前只有 RegExMatch 和 RegExReplace 支持正则调出.
在 AutoHotkey 中正则调出的语法为 (?CNumber:Function), 其中 Number 和 Function 都是可选的. 只有在指定了 Function才允许使用冒号 ':', 而如果省略 Number 则冒号也可以省略. 如果指定的 Function 不是自定义的函数名称, 则会出现编译错误且不会开始模式匹配.
如果省略 Function, 则必须在名为 pcre_callout 的变量中指定函数名称. 如果全局变量和局部变量都以这个名称存在, 则以局部变量为准. 如果 pcre_callout 不包含用户定义的函数名, 那么省略 Function 的正则调出将被忽略.
MyFunction(Match, CalloutNumber, FoundPos, Haystack, NeedleRegEx) { ... }
正则调出函数最多可以定义 5 个参数:
这些名称只是提示性的. 实际中可以使用其他的名称.
模式匹配是继续进行或失败, 取决于正则调出函数的返回值:
例如:
Haystack := "The quick brown fox jumps over the lazy dog." RegExMatch(Haystack, "i)(The) (\w+)\b(?CCallout)") Callout(m,*) { MsgBox "m[0]=" m[0] "`nm[1]=" m[1] "`nm[2]=" m[2] return 1 }
在上面的例子中, 对于匹配正则调出之前的那部分模式的每个子字符串都会调用一次 Callout. 使用 \b 排除匹配到不完整的单词, 例如 The quic, The qui, The qu, 等等.
通过 A_EventInfo 访问 pcre_callout_block 结构可以获得附加信息.
version := NumGet(A_EventInfo, 0, "Int") callout_number := NumGet(A_EventInfo, 4, "Int") offset_vector := NumGet(A_EventInfo, 8, "Ptr") subject := NumGet(A_EventInfo, 8 + A_PtrSize, "Ptr") subject_length := NumGet(A_EventInfo, 8 + A_PtrSize*2, "Int") start_match := NumGet(A_EventInfo, 12 + A_PtrSize*2, "Int") current_position := NumGet(A_EventInfo, 16 + A_PtrSize*2, "Int") capture_top := NumGet(A_EventInfo, 20 + A_PtrSize*2, "Int") capture_last := NumGet(A_EventInfo, 24 + A_PtrSize*2, "Int") pad := A_PtrSize=8 ? 4 : 0 ; 补足 64 位的数据偏移. callout_data := NumGet(A_EventInfo, 28 + pad + A_PtrSize*2, "Ptr") pattern_position := NumGet(A_EventInfo, 28 + pad + A_PtrSize*3, "Int") next_item_length := NumGet(A_EventInfo, 32 + pad + A_PtrSize*3, "Int") if (version >= 2) mark := StrGet(NumGet(A_EventInfo, 36 + pad + A_PtrSize*3, "Int"), "UTF-8")
有关详情, 请参阅 pcre.txt, NumGet 和 A_PtrSize.
在模式的选项中包含 C 来启用自动调出模式. 在这种情况下的正则调出相当于在模式里的每项前插入了 (?C255). 例如, 下面的模板可以用来调试正则表达式:
; 设置默认的正则调出函数. pcre_callout := "DebugRegEx" ; 使用自动调出选项 C 来调用 RegExMatch. RegExMatch("xxxabc123xyz", "C)abc.*xyz") DebugRegEx(Match, CalloutNumber, FoundPos, Haystack, NeedleRegEx) { ; 请参阅 pcre.txt 了解这些字段的说明. start_match := NumGet(A_EventInfo, 12 + A_PtrSize*2, "Int") current_position := NumGet(A_EventInfo, 16 + A_PtrSize*2, "Int") pad := A_PtrSize=8 ? 4 : 0 pattern_position := NumGet(A_EventInfo, 28 + pad + A_PtrSize*3, "Int") next_item_length := NumGet(A_EventInfo, 32 + pad + A_PtrSize*3, "Int") ; 指出 >>当前匹配<<. _HAYSTACK:=SubStr(Haystack, 1, start_match) . ">>" SubStr(Haystack, start_match + 1, current_position - start_match) . "<<" SubStr(Haystack, current_position + 1) ; 指出 >>要计算的下一个项目<<. _NEEDLE:= SubStr(NeedleRegEx, 1, pattern_position) . ">>" SubStr(NeedleRegEx, pattern_position + 1, next_item_length) . "<<" SubStr(NeedleRegEx, pattern_position + 1 + next_item_length) ListVars ; 按下 Pause 继续. Pause }
正则调出在当前的半线程中执行, 但在正则调出函数返回后将恢复 A_EventInfo 原来的值.
在一些可以确定不会发生匹配的情况下, 则会对 PCRE 进行优化来提早中止. 对于在这些情况中的所有正则调出, 可能需要在模式的开始处指定 (*NO_START_OPT) 来禁用这种优化.
unixetc