正则表达式调出

正则调出提供了一种在正则表达式模式匹配过程中临时将控制权传递给脚本的方法. 关于 PCRE 标准调出功能的详细信息, 请参阅 pcre.txt.

目前只有 RegExMatchRegExReplace 支持正则调出.

目录

语法

在 AutoHotkey 中正则调出的语法为 (?CNumber:Function), 其中 NumberFunction 都是可选的. 只有在指定了 Function才允许使用冒号 ':', 而如果省略 Number 则冒号也可以省略. 如果指定的 Function 不是函数对象的名称, 则会出现编译错误且不会开始模式匹配.

如果省略 Function, 则必须定义默认的正则调出函数名 pcre_callout. 如果没有定义 pcre_callout, 那么省略 Function 的正则调出将被忽略.

正则调出函数

MyFunction(Match, CalloutNumber, FoundPos, Haystack, NeedleRegEx)
{
    ...
}

正则调出函数最多可以定义 5 个参数:

这些名称只是提示性的. 实际中可以使用其他的名称.

警告: 不支持在 RegExReplaceRegExMatch 在被调用期间更改其输入参数, 这可能会导致不可预测的行为.

模式匹配是继续进行或失败, 取决于正则调出函数的返回值:

例如:

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, 等等.

如果在调出期间修改了 RegEx 函数的任何输入参数, 则该行为是未定义的.

EventInfo

通过 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, NumGetA_PtrSize.

自动调出

在模式的选项中包含 C 来启用自动调出模式. 在这种情况下的正则调出相当于在模式里的每项前插入了 (?C255). 例如, 下面的模板可以用来调试正则表达式:

; 调用带有自动调出选项 C 的 RegExMatch.
RegExMatch("xxxabc123xyz", "C)abc.*xyz")

; 定义默认的正则调出函数.
pcre_callout(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