정규식 콜아웃
정규식 콜아웃 (Regular Expression Callouts)
AutoHotkey의 RegEx 콜아웃(정규식 매칭 도중 일시적으로 제어권을 스크립트에 넘기는 기능)의 문법과 사용법을 설명하는 문서예요.
출처: 문서
본문
RegEx 콜아웃(callout)은 정규식 패턴 매칭 도중에 일시적으로 제어권을 스크립트로 넘기는 수단을 제공해요. PCRE 표준 콜아웃 기능에 대한 자세한 정보는 pcre.txt를 참조해요.
RegEx 콜아웃은 현재 RegExMatch와 RegExReplace에서만 지원돼요.
목차 (Table of Contents)
- Syntax (문법)
- RegEx Callout Functions (RegEx 콜아웃 함수)
- EventInfo
- Auto-Callout (자동 콜아웃)
- Remarks (주의 사항)
문법 (Syntax)
AutoHotkey에서 RegEx 콜아웃의 문법은 (?CNumber:Function)이에요. Number와 Function은 둘 다 선택 사항이에요. 콜론 ':'은 Function을 지정할 때만 허용되며, Number를 생략하면 생략할 수 있어요.
콜아웃 함수는 공식적으로 정의하거나, RegExMatch나 RegExReplace를 호출한 함수의 범위(지역 또는 전역) 안에서 변수에 할당함으로써 제공해야 해요. Function을 생략하면 기본값은 pcre_callout이에요. 변수를 찾지 못하거나 그 값이 함수 객체가 아니면 오류가 던져져요.
RegEx 콜아웃 함수 (RegEx Callout Functions)
*MyFunction*(Match, CalloutNumber, FoundPos, Haystack, NeedleRegEx)
{
...
}
RegEx 콜아웃 함수는 최대 5개의 매개변수를 정의할 수 있어요:
- Match: 지금까지의 매치에 대한 정보를 담은 RegExMatchInfo 객체를 받아요.
- CalloutNumber: RegEx 콜아웃의 Number를 받아요.
- FoundPos: 현재 잠재적 매치의 위치를 받아요.
- Haystack: RegExMatch 또는 RegExReplace에 전달된 Haystack을 받아요.
- NeedleRegEx: RegExMatch 또는 RegExReplace에 전달된 NeedleRegEx를 받아요.
이 이름들은 단지 제안일 뿐이에요. 실제 이름은 달라질 수 있어요.
경고: 콜아웃 중 RegExReplace 또는 RegExMatch의 입력 매개변수를 변경하는 것은 지원되지 않으며 예측할 수 없는 동작을 일으킬 수 있어요.
RegEx 콜아웃 함수의 반환 값에 따라 패턴 매칭이 진행되거나 실패할 수 있어요:
- 함수가 0을 반환하거나 숫자 값을 반환하지 않으면, 매칭이 평소대로 진행돼요.
- 함수가 1 이상을 반환하면, 현재 지점에서 매칭이 실패하지만 다른 매칭 가능성의 테스트는 계속돼요.
- 함수가 -1을 반환하면, 매칭이 중단돼요.
- 함수가 -1보다 작은 값을 반환하면, 그것은 PCRE 오류 코드로 취급되고 매칭이 중단돼요. 이것은 RegExMatch와 RegExReplace가 예외를 던지게 하며, 예외 객체의 Extra 프로퍼티가 오류 코드를 담아요.
예를 들어:
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은 RegEx 콜아웃 앞의 패턴 부분과 일치하는 각 하위 문자열에 대해 한 번씩 호출돼요. \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, NumGet 및 A_PtrSize를 참조해요.
자동 콜아웃 (Auto-Callout)
패턴의 옵션에 C를 포함하면 자동 콜아웃 모드가 활성화돼요. 이 모드에서 (?C255)와 동일한 RegEx 콜아웃이 패턴의 각 항목 앞에 삽입돼요. 예를 들어, 다음 템플릿은 정규식을 디버깅하는 데 사용될 수 있어요:
*; 자동 콜아웃 옵션 C로 RegExMatch 호출.*
RegExMatch("xxxabc123xyz", "C)abc.*xyz")
*; 기본 RegEx 콜아웃 함수 정의.*
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
}
주의 사항 (Remarks)
RegEx 콜아웃은 현재 유사 스레드(quasi-thread)에서 실행되지만, RegEx 콜아웃 함수가 반환된 후에는 A_EventInfo의 이전 값이 복원돼요.
PCRE는 어떤 경우 매치가 불가능하다고 판단하면 일찍 중단하도록 최적화돼 있어요. 그런 경우 모든 RegEx 콜아웃이 호출되게 하려면, 패턴의 시작 부분에 (*NO_START_OPT)를 지정해 이 최적화를 비활성화해야 할 수 있어요.