⚠ 이 강좌는 오토핫키 v1을 다룹니다
지금 보시는 강좌는 구버전 오토핫키(v1.1)를 다루고 있습니다. 따라서 본 강좌의 내용은 현재 최신 오토핫키 버전 (v2.0)과 호환되지 않습니다. 구버전의 정보가 필요한 것이 아니라면, 가능한 한 새로운 사이트에 작성한 v2 강좌(https://ahkv2.pnal.dev)를 봐주시길 바랍니다.
사실 이 부분은 넣을까 말까 고민했던 부분이기도 합니다. 사실상 문자열을 다루는 함수 중에서는 가장 복잡하고 어렵기 때문입니다. 실제로 나 오토핫키 좀 한다 하시는 분들 중에 정규식을 못 다루시는 분들도 계셨고요.
기초 강좌에 어울리지 않는 강이라는 뜻입니다. 아마 타 프로그래밍 언어 배우셨던 분들에게 여쭤보셔도 "세상에, 정규식을 기초 강좌에서 가르쳐?" 같은 반응이겠지요.
그렇지만 한번쯤 소개시켜드리고 싶었습니다. 문자열을 다루는 부분에선 끝판왕일 정도로 범용성이 좋기 때문입니다.
기초 강좌이기 때문에, 최대한 자주 쓰이는 방식으로만 다루도록 하겠습니다. 이거 보고 다른데 가서 "여기가 정규식 맛집이더라", "여기서 정규식 다 배웠다"라고는 말씀하시면 안됩니다... ㅋㅋ; 여러분은 지금 여기서 정규식의 "ㅈ"정도 배우는 수준이니까요.
2020.01.16 추가)
이 강은 RegExMatch를 상세히 설명하고 있지 않습니다. 정규식의 자세한 사용법을 따로 강좌하였으니, 관심있으신 분은 아래 링크를 참고해주세요.
파싱
지금까지 문자열 관련 함수들을 등장시키면서 파싱이 뭔지 말씀을 안드렸네요. 파싱은 "문자열을 가공하여 유의미한 정보로 만드는" 과정을 뜻합니다. 유의미한 정보는 본인 나름껏의 기준이고요, 하다못해 숫자와 영어가 섞인 문자열에서 숫자만 가져온다면 그것은 파싱을 한 것입니다.
즉, 우리가 지난 강에 배웠던 SubStr()은 파싱을 위한 함수입니다. 이번에 배우는 RegExMatch()도 그렇고요.
정규식
정규식(RegEx)은 "정규 표현식(Regular Expression)"의 줄임말로, 원래 특정 문자열을 가공하기 위해 쓰는 식을 뜻합니다. 그렇지만 오토핫키에서 "정규식"이라 하면 보통 그러한 식을 포함한 RegExMatch()구문을 뜻하는 경우가 많습니다.
오토핫키에서 명령어에 RegEx가 붙어있다면 그것은 정규식 함수이며, 이 함수의 매개변수로 정규식을 사용해주는 것입니다.
제가 알기로 오토핫키에선 RegExMatch()와 RegExReplace()가 있는데 RegExMatch()만 설명드리도록 하겠습니다.
RegExMatch()
RegExMatch()는 특정 문자열이 몇 번째 글자로 등장하는 지를 반환해주는 함수입니다.
RegExMatch(Haystack, NeedleRegEx , OutputVar)
- Haystack: 전체 문자열의 변수명을 적어주시면 됩니다.
- NeedleRegEx: 이 부분에서 정규식을 사용해줍니다. 따옴표를 이용하여 문자열 취급을 해주셔야합니다. 이 부분 전체를 "패턴"이라고 합니다.
- OutputVar: 가공된 문자열이 담기는 변수입니다.
반환 값은 패턴으로 찾은 문자열의 위치이기 때문에 이 식을 변수에 대입해주면 해당 변수는 정수값을 가집니다. (예: var := RegExMatch(~~~)는 var 변수에 정수값이 담깁니다.)
OutputVar1에는 아래에서 설명할 "(.*)에 해당되는 문자열"이 담깁니다. OutputVar를 써주었는데, OutputVar1을 사용하는 것에 주의해주셔야합니다. 이번 강 서론에 드렸던 "자세한 정규식 강좌"를 참고하시면 나오는 내용인데, 여기서는 그냥 OutputVar1의 형태로 써주자구요.
NeedleRegEx부분 작성 요령
정규식은 사용 방법이 정말 복잡합니다. 그 중에서 가장 많이 사용되는 한 가지만 강좌하려고 합니다.
바로 .*입니다.
원래 쩜(.)따로 별(*)따로 의미가 있지만, 워낙 같이 쓰이는 경우가 많다 보니 아예 오토핫키 공식 문서에서도 dot-star이라고 하나로 묶어서 칭하고있습니다. 뜻은 "모든 문자"라고 해석하시면 됩니다. 기초 강좌이니 우선 이정도만 알아두시면 됩니다.
NeedleRegEx엔 "패턴"을 써줘야합니다. 방금 배운 dot-star을 이용해서요. 아래 예시는 dot-star를 이용한 패턴의 예시입니다.
aaa(.*)ccc
→ aaa와 ccc사이에 있는 모든 문자열
동해물과(.*)마르고
→ 동해물과와 마르고 사이에 있는 모든 문자열
(.*)abc123
→abc123 전에 있는 모든 문자열
예시
정규식은 많은 예제를 보며 감을 잡을 수밖에 없습니다. 저도 정규식을 잘 다루는 게 아니라 기초적인 예시밖에 없네요.
우선 공식 도움말의 예제입니다.
FoundPos := RegExMatch("abcXYZ123", "abc(.*)123", SubPat)
MsgBox, %SubPat%`, %SubPat1%
FoundPos에는 찾은 문자열의 위치가 들어갑니다. 주어진 문자열은 abcXYZ123인데, NeedleRegEx부분엔 abx(.*)123으로 패턴이 작성되어있네요. 해당 패턴은 주어진 문자열의 첫 글자부터 일치합니다. 따라서 FoundPos변수에는 1이 담깁니다.
SubPat에는 (.*)에 해당되는 문자열이 패턴을 포함하여 담깁니다. 즉, abc(.*)123에 해당하는 문자열이 담기기 때문에, SubPat변수에는 abcXYZ123이 담깁니다.
이와 반대로, SubPat1 변수에는 (.*)에 해당하는 문자열이 패턴을 포함하지 않고 담깁니다. 즉, (.*)부분만 그대로 담기기 때문에 변수의 값은 XYZ가 됩니다.
다른 예시를 볼까요.
var := "<meta name=""apple-mobile-web-app-title"" content=""NAVER"" />"
말씀 드린적이 없는 것 같은데, 따옴표가 문자열 표시인 곳에서 따옴표를 표시하려면 두 번 써주시면 됩니다. ("")
위 예시에선 var 변수에 아래와 같은 내용이 담긴 셈입니다.
<meta name="apple-mobile-web-app-title" content="NAVER" />
우리는 여기서 NAVER부분만 가져와보도록 하겠습니다.
RegExMatch(var, "content=""(.*)""", a)
content="(.*)" 부분이 정규식이 됩니다. 따옴표를 표현하기 위해 두 번씩 써주고, 패턴의 처음과 끝에 한번씩 더 써주었습니다(문자열임을 표시하기 위한 따옴표). 그래서 "content=""(.*)"""라는 기괴한 식이 나오게 되었습니다.
a1변수에는 NAVER가 담기겠네요.
var := "<meta name=""apple-mobile-web-app-title"" content=""NAVER"" />"
RegExMatch(var, "content=""(.*)""", a)
MsgBox, %a1%
정규식을 기초 강좌 커리큘럼에 넣은 것이 올바른 선택이었는지는 저도 모르겠습니다. 다만 제가 이번 강좌에서 여러분께 바라는 것은, "정규식을 완벽하게 알아야한다"가 아닌 "이런 방식도 있구나"정도입니다. 추후에 필요하실때 다시 찾아볼 정도의 기억만 하시면 됩니다.
정규식이 이런거다 정도만 강좌했기 때문에 어디가서 정규식 배웠다고 하면 저 혼납니다.. ㅋㅋ;
여러분이 조금 더 능력있고, 오토핫키를 떡주무르듯이 다루실 때 배워도 늦지 않습니다. 지금은 보기만 하자구요.
< 63. SubStr() | 64. 정규식 : RegExMatch | 65. 프로그래밍 문제 (15) >