정규 표현식 Callouts [v1.0.90+]

외부호출(Callouts)은 정규 표현식 일치 작업 중간에 임시로 제어를 스크립트에 넘기는 수단을 제공합니다. PCRE-표준 callout 특징에 관한 더 자세한 정보는 pcre.txt를 참조하십시오.

콜아웃은 현재 RegExMatch 그리고 RegExReplace만 지원합니다.

구문

오토핫키에서 callout 구문은 (?CNumber:Function)입니다. NumberFunction 모두 선택적입니다. 쌍점 ':'은 Function이 지정되었을 경우에만 허용됩니다. Number를 생략하면 선택적입니다. Function이 지정되었지만 사용자-정의 함수의 이름이 아니면, 컴파일 에러가 일어나고 패턴-일치가 시작되지 않습니다.

Function을 생략하면, 함수 이름을 반드시 pcre_callout이라는 이름의 변수에 지정해야 합니다. 이 이름으로 전역 변수와 지역 변수가 모두 존재하면, 지역 변수가 우선 순위를 갖습니다. pcre_callout에 사용자-정의 함수 이름이 없으면, Function이 생략된 외부호출은 무시됩니다.

Callout 함수

Function(Match, CalloutNumber, FoundPos, Haystack, NeedleRegEx)
{
    ...
}
선택

Callout 함수는 매개변수를 다섯 개까지 정의할 수 있습니다:

  • Match: 필요하면 배열 변수의 생성도 포함해서 RegExMatch의 UnquotedOutputVar와 동등합니다.
  • CalloutNumber: 콜아웃의 Number를 받습니다.
  • FoundPos: 현재의 잠재적인 부합의 위치를 받습니다.
  • Haystack: RegExMatch 또는 RegExReplace에 건네어진 Haystack을 받습니다.
  • NeedleRegEx: RegExMatch 또는 RegExReplaceReceives에 건네어진 NeedleRegEx를 받습니다.

이 이름들은 그냥 제시 용일 뿐입니다. 실제 이름은 다를 수 있습니다.

패턴-일치는 콜아웃 함수의 결과에 따라 계속 진행되거나 실패합니다:

  • 콜아웃 함수가 0을 돌려주거나 숫치 값을 돌려주지 않으면, 부합은 정상대로 진행됩니다.
  • 함수가 1 이상을 돌려주면, 현재 위치의 부합은 실패합니다. 그러나 다른 부합의 가능성 테스트는 계속 진행됩니다.
  • 함수가 -1을 돌려주면, 부합을 포기합니다.
  • 함수가 -1보다 작은 값을 돌려주면, PCRE 에러 코드로 간주하고 부합을 포기합니다. RegExMatch는 빈 문자열을 돌려주는 반면에, RegExReplace는 원래의 Haystack을 돌려줍니다. 어느 경우든, ErrorLevel에 에러 코드가 담깁니다.

예를 들어:

Haystack = The quick brown fox jumps over the lazy dog.
RegExMatch(Haystack, "i)(The) (\w+)\b(?CCallout)")
Callout(m) {
    MsgBox m=%m%`nm1=%m1%`nm2=%m2%
    return 1
}
선택 | 내려받기

위의 예제에서, Func는 콜아웃 앞의 패턴 일부에 부합하는 부문자열마다 한 번씩 호출됩니다. \b는 부합에서 불완전한 단어들을 배제하는 데 사용됩니다. 예를 들어 The quic, The qui, The qu, 등등은 단어가 아니므로 제외됩니다.

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)
subject           := NumGet(A_EventInfo,  8 + A_PtrSize)
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)
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를 참조하십시오.

Auto-Callout

패턴의 옵션에 C를 포함하면 auto-callout 모드가 켜집니다. 이 모드에서 (?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의 이전 값이 복구됩니다. RegExMatch 또는 RegExReplace가 돌아오기 바로 전까지 ErrorLevel은 설정되지 않습니다.

PCRE는 어떤 경우에 부합이 불가능하다고 판단되면 일찍 취소되도록 최적화되어 있습니다. 그런 경우라면 모든 콜아웃에 대하여 이런 최적화를 끌 필요가 있습니다. 패턴의 처음에 (*NO_START_OPT) 를 지정하면 됩니다. 이 기능은 v1.1.05 이상을 요구합니다.