끝나지 않는 프로그래밍 일기


1. 하위 표현식(Subexpression)


하위 표현식(Subexpression)이란, 특정 패턴, 표현식을 하나의 항목으로 처리하는 것입니다. 이 하위 표현식을 사용하려면 소괄호를 사용해야 합니다. 참고로, 소괄호 역시도 메타 문자이기 때문에, 소괄호 그 자체를 찾으려면 \(, \)와 같이 이스케이프 해주어야만 합니다. 아래 예를 한번 보도록 합시다.


Reg. Expression:

abc{2}

Text:

abcc

abcabc


위의 일치된 텍스트를 보시면, 예상과는 다르게 abcabc가 아닌 abcc가 일치되었습니다. 무엇이 잘못되었나 살펴보았더니, {2}는 앞에 등장한 문자의 범위를 지정하는 녀석입니다. {2} 앞에 있는 문자는 c이고, c가 2번 등장하니 abcc가 일치될 수 밖에 없었습니다. 이제, 우리가 배울 하위 표현식이란 녀석을 통해 이 문제를 해결해보도록 합시다.


Reg. Expression:

(abc){2}

Text:

abcc

abcabc


위에 쓰인 정규 표현식에서 (abc)는 하위 표현식입니다. 하위 표현식으로 사용되었기에, abc는 하나의 항목으로 처리됩니다. 이번에는 {2} 앞에 등장하는 녀석이 하위 표현식이니, 이 하위 표현식이 연속으로 2번 등장하는 녀석을 찾습니다(abcabc). 일치된 텍스트를 살펴보니, abcc가 아닌 abcabc로 정상적으로 동작함을 확인하실 수 있습니다. 예제를 하나 더 보도록 합시다.


Reg. Expression:

\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}

Text:

192.168.0.1

127.0.0.1


위에 쓰인 정규 표현식을 살펴보면, \d{1,3}이 숫자가 최소 한번, 최대 세번은 연속적으로 등장하고 그 다음에 등장하는 \.는 . 문자를 나타냅니다. 일치된 텍스트에선 IP 주소로 보이는 텍스트들이 일치가 되었습니다. 위의 정규 표현식에서도 하위 표현식을 사용할 수 있습니다. 아래와 같이 말입니다.


Reg. Expression:

(\d{1,3}\.){3}\d{1,3}

Text:

192.168.0.1

127.0.0.1


위에 쓰인 정규 표현식을 살펴보면, 하위 표현식이 쓰였는데 (\d{1,3}\.){3}은 \d{1,3}\.이 정확히 3번 등장해야 하므로, \d{1,3}\.\d{1,3}\.\d{1,3}\.와 같습니다. 하위 표현식으로 나타내니, 한결 더 간단해졌죠?


2. 하위 표현식의 중첩


방금 예제로는 유효한 IP 주소를 찾아내지 못합니다. 192.168.0.1 뿐만 아니라 123.456.789.101 같은 녀석들도 일치하기 때문입니다. 이런 문제는 지금부터 배우게 될 하위 표현식의 중첩을 통해 해결할 수 있습니다. (하위 표현식의 중첩이란 즉, 하위 표현식 안에 또다른 하위 표현식을 둘 수 있다는 말입니다.) 이 하위 표현식의 중첩을 통해 방금 보았던 예제를 수정해보도록 합시다.


정규 표현식에서는 다른 언어들처럼 숫자를 비교하는 연산자는 없습니다. 일치시키거나 치환할 수 밖에 없습니다. 비교 연산자가 주어지지 않은 상태에서, 유효한 아이피 주소를 찾으려면 숫자가 한자리 혹은 두 자리 숫자이거나, 1로 시작하는 세자리 숫자이거나, 2로 시작하며 두번째 자리 숫자가 0~4 사이의 모든 세자리 숫자거나, 25로 시작하며 세번째 자리 숫자가 0~5 사이의 모든 세자리 숫자를 찾아야만 합니다. 정리해보자면 아래와 같습니다.


● 모든 한자리 혹은 두자리 숫자 = \d{1,2}

● 1로 시작하는 세자리 숫자 = 1\d{2}

● 2로 시작하며 두번째 자리 숫자가 0~4 사이의 모든 세자리 숫자 = 2[0-4]\d

25로 시작하며 세번째 자리 숫자가 0~5 사이의 모든 세자리 숫자 = 25[0-5]


그리고 이 4가지 경우에서 하나라도 일치할 경우를 생각해서 OR 연산자인 |를 사용해야 합니다. 아래는 위의 조건들을 정규 표현식으로 나타낸 예제입니다.


Reg. Expression(5.5 기준):

(((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))\.){3}((1[0-9]{2})|(2[0-4]\d)|(25[0-5])|(\d{1,2}))

Text:

192.168.0.1

123.456.789.101

127.0.0.1

10.1.2.4


위의 정규 표현식에서 4가지 경우를 모두 적용했습니다. 일치된 텍스트를 보시면 모두 유효한 아이피 주소임을 확인하실 수 있습니다.


하위 표현식에 대한 설명은 여기까지 하도록 하겠습니다. 수고하셨고, 다음 강좌에서는 역참조에 대해 설명합니다.