정규식으로 날짜를 검색하는 것은 쉽습니다. 날짜에 해당하는 문자열이 일정한 패턴만 갖고 있다면 말입니다. 가령,
2011-02-29 마누라 생일이다. 이번에는 꼭 까먹지 말아야지.
위의 텍스트에서 날짜만 매치시키려면? 이제는 너무도 쉬운 문제일 것입니다.
\d{4}-\d{2}-\d{2}
위와 같이 하면 됩니다. 물론 \d는 [0-9]로 바꿔 써도 됩니다. 그런데 여기서 날짜 포맷이 잘못됐다면 어떻게 될까요? 가령 위 문제인 2011-02-29처럼 말입니다. 2011년은 윤년이 아니므로 2월이 28일까지만 있습니다. 이처럼 존재할 수 없는 날짜를 빼고 매치한다는 게 가능할까요?
사실 이런 식의 문제를 정규식으로 처리하기에는 한계가 있습니다. 이는 c나 자바, php 등의 프로그래밍 언어로 처리하는 게 훨씬 더 쉽고 효율적입니다. 정규식으로는 혹 가능하다 해도 훨씬 더 어렵고 처리 속도 또한 느릴 수밖에 없습니다.
물론 방금 내드린 문제의 해결이 불가능한 것은 아닙니다. 이해를 쉽게 하기 위해 경우의 수를 좀 좁혀서 생각해 보겠습니다. 무슨 말이냐면, 연도가 2011년과 2012년의 두 가지만 있다고 가정해 보자는 것입니다. 그리고 편의상 월도 2월에만 국한시켜 보겠습니다.
아시다시피 2012년은 윤년입니다. 따라서 연도가 2011이라면 2월은 28일까지만 올 수 있고 2012라면 29까지 올 수 있습니다.
2011-02-28
2011-02-29
2012-02-29
두 번째 줄만 빼고 매치되면 성공입니다. 정규식은 아래와 같습니다.
20((11-02-(([0-1][0-9])|([2][0-8])))|(12-02-(([0-1][0-9])|([2][0-9]))))
으으윽~ 갑자기 골이 아파오면서 눈텡이가 빠질 것 같은... 그렇습니다. 그래서 이런 식의 판단이 들어가는 문제엔 가급적 정규식을 쓰지 않는 게 좋다고 말씀드린 것입니다. 이 정규식을 작성하면서 저도 눈깨나 아팠답니다. 괄호 짝을 맞추느라고 말입니다. 여기서 윤년의 공식을 한번 볼까요?
아시다시피 4로 나눠지면 윤년입니다. 그러나 100으로 나눠지면 평년입니다. 반전이죠? 그런데 반전이 한번 더 있습니다. 400으로 나눠지면 윤년이 된다는 것입니다. 예를 볼까요?
1900년은? 4로 나눠지지만 100으로 나눠지고 400의 배수는 아니니 평년입니다.
2000년은? 뭐, 더 이상 부연설명이 필요 없겠죠? 윤년입니다.
2010년은? 애초에 4의 배수 자체가 아니니 평년입니다.
2012년은? 4의 배수이고 100으로 안 나눠지므로 윤년입니다.
이를 php 코드로 만들어 볼까요?
<?php
function isLeap($y) {
$b = 0; // 윤년 여부를 나타내는 플래그.
if (($year % 4) == 0) {
$b = 1; // 4로 나눠지면 일단 윤년.
if (($year % 100) == 0) {
$b = 0; // 100으로 나눠지면 평년.
if (($year % 400) == 0)
$b = 1; // 400으로 나눠지면 윤년.
}
}
return $b;
}
?>
쉽지요? 프로그래밍을 조금만 해보신 분이라면 금방 만들 수 있는 수준의 코딩입니다. 게다가 얼마나 간결합니까. 한눈에 봐도 이게 뭐 하는 넘인지 필이 팍 오잖아요. 그런데 정규식으로 이런 패턴 매치를 가능케 하는 것은 불가능합니다. 정규식에는 4의 배수인지 아닌지를 판단할 수 있는 연산자나 문법이 없습니다. 그저 온갖 경우의 수를 나열하는 게 고작입니다. 다만 해당 연도가 제한되어 있다면, 즉 경우의 수가 몇 개 안 된다면 억지로라도 정규식을 작성할 수는 있다는 정도입니다.