정규표현식 메모 조건식 또는 조건문 #1 도구

참조1 참조2

데이타             bc bd abc abd abf

정규표현식       (a)?b(?(1)c|d)

perl 에서 이렇게 돌려봤다.

use 5.010;
@data = qw(bc bd abc abd abf);
$regex = qr{(a)?b(?(1)c|d)};

for(@data) {
    say $_ if /$regex/;
}

결과는 

bd
abc
abd

bd와 abc는 예상한 대로 였는데 abd가 예상밖이었다.
펄 최신판(5.20.x)을 쓰고 있는데 혹시 버전업이 되면서 버그가 생긴건가 싶어서 우분투에 깔려있는 5.18.x 의 펄로 실행해봐도 결과는 같았다. 조건표현식에서 진도가 딱 멈췄다. if else 는 되는데 if then은 왜 안되는걸까?
글의 첫머리에 링크해놓은 곳에서 그것에 대한 설명을 발견했다. 

먼저 $_ 로 출력할 것이 아니라 $&(매치된 부분만 출력)로 say문장을 바꿔서 실행해보면 다음과 같다. 기호(&)가 요상하게 표시가 되는데 숫자 7 위에 있는 기호이다.

say $& if /$regex/;

결과는 
bd
abc
bd

abd 전체가 매치된 것이 아니라 bd만 매치된 것 이었는데 $_로 출력을 하니까 전체문장인 abd가 보였던 것이다.

조건표현식은 다음과 같은 구조를 갖는다

(조건표현)?
여기서 ? 는 수량자이다. 없거나 하나 있거나. (a)? 는 a가 있거나 없거나를 말한다.


(조건표현)?문장

공통부분. (a)?b 는 a가 있으면 ab 가 되고 a가 없으면 b가 된다. b는 언제나 포함되니까 공통부분이다.


(조건표현)?문장(?(캡쳐그룹))

(?(캡쳐그룹))는 캡쳐그룹이 있는가 없는가를 나타낸다. 물음표바깥에도 안쪽에도 괄호가 있다. 조건정규표현식의 문법이다. (a)?b(?(1)) 에서 숫자1은 왼쪽에 있는 첫번째그룹인 (a)를 나타낸다. a가 있는가하고 물어보는 것이다. 그룹은 괄호로 친 부분을 나타내는 거니까 만약 (a)(b)(c)(?(3))하면 숫자3은 (c)를 나타낸다. (b)는 숫자2다. 캡쳐그룹이 많아져서 또는 다른 이유로 특정그룹의 지정을 문자로 할 수도 있다. 캡쳐그룹에 적당한 이름을 주고 조건문에서 그 이름을 쓰는 방법이다. 펄에서는 이렇게 한다. 

(a)? 를    (?<here>a)  이렇게 here라는 이름을 주고
(?(1)) 를  (?(<here>)) 이렇게 here를 참조한다.

(a)?b(?(1)c|d)

(?<here>a)b(?(<here>)c|d)

물음표가 늘어나서 조금 복잡해보이지만 이해 못할 바는 아니다.

(?<here>a)를 (?'here'a)  또는 (?P<here>a) 이렇게 할 수도 있다.

(조건표현)?문장(?(캡쳐그룹)예|아니오)

조건이 참이면 [예] 거짓이면 [아니오]가 선택된다. 둘사이는 | 로 구분되어있다. [예]가 또는 [아니오]가 없을 수도있다. 즉 (조건표현)?문장(?(캡쳐그룹)예) 또는 (조건표현)?문장(?(캡쳐그룹)|아니오) 이렇게 쓸 수 있다.
 (a)?b(?(1)c|d)를 해석해보면 그룹1인 (a)가 있으면 c를 선택하고 (a)가 없으면 d를 선택한다는 뜻이다. b를 넣어서 전체적으로 보면 (a)가 있는 경우는 abc가 선택되고 (a)가 없는 경우는 bd 가 선택되는 것이다.

이제 bd와 abc가 선택되는 것은 조건식에 따라 나타난 결과이고 abd가 선택된 이유는 $&로 출력해 봐서 알았겠지만 abd의 bd가 선택이 되니까 전체문장이 나타난 것이다. abd를 선택에서 뺄려면 문장의 처음을 표시하는 ^ 기호를 쓰면된다. 이기호를 쓰면 bd는 선택되지만 abd는 선택되지 않는다.  즉,

^(a)?b(?(1)c|d)

괄호바깥에 ^ 가 와야지 괄호안에 들어가 버리면 a 가 없을때 ^까지 같이 사라져 버리지만 이렇게 괄호바깥으로 빼버리면 a가 없어도 ^는 살아남아 ^b가 된다. 

^(a?)b(?(1)c|d) 이렇게 수량자 물음표를 괄호안에 집어넣으면 어떻게 될까?

a가 없는경우는 ^()b(?(1)c|d)가 되고 a가 있는 경우는 ^(a)b(?(1)c|d) 가 된다. 둘다 캡쳐그룹은 살아있다. 즉 괄호는 살아있다. 앞의 경우는 공백으로 뒤의 경우는 a가 있는 것만이 다르지 캡쳐그룹자체는 여전히 있다. 그래서 ?(1)이 항상 참이 되어 c 만 선택된다. 그래서 abc와 bc만을 선택하게 된다. 주의하도록 하자.

덧글

댓글 입력 영역