화요일의 정규식 6주차 문제는 IP 주소 형식을 체크하는 것입니다. IP 주소 형식은 우리가 흔히 아는 255.255.255.255 같이 4개의 파트로 이루어진 10진수 형태 외에도 각 파트를 8진수, 16진수로 표현한 형식도 가능하며(예. 0xff.0xff.0xff.0xff) 또는 아예 각 파트를 자리수로 보아 0xffffffff와 같이 표현하거나 이를 10진수, 8진수 형태로 표현한 형식도 있습니다.
숫자만으로 형식이 구성되는 것은 간편해서 좋지만, 언제나 그렇듯 범위의 유효성을 검증하는 일이 성가신 문제였습니다. 기존에 설명한 기법만으로도 충분히 해결할 수 있는 문제이므로 이번 문제에서는 특별한 기법에 대해 소개하지 않고 바로 해답으로 넘어갑니다.
물론, 제 답은 하나의 예일 뿐 다른 답(심지어 더 좋은 답)이 있을 수도 있음을 기억하시고 꼭 직접 풀어보셨으면 좋겠습니다.
해답 및 풀이
[toggle txt_show="6주차 풀이 보기" txt_hide="6주차 풀이 감추기"]해답
정규표현식 : /^(((0x[\dA-F]{2}|0[1-3]?[0-7]{1,3}|1?\d{1,2}|2[0-4]\d|25[0-5])(\.(?!$)|$)){4}|0x[\dA-F]{8}|0[1-3][0-7]{9,10}|[1-3]?\d{1,9}|4[0-1]\d{8}|42[0-8]\d{7}|429[0-3]\d{6}|4294[1-8]\d{5}|42949[0-5]\d{4}|429496[0-6]\d{3}|4294967[0-1]\d{2}|42949672[1-8]\d|429496729[0-5])$/
풀이
앞서 설명드린 대로 이번 문제는 크게 두 종류의 형식이 있습니다. 하나는 4개의 파트로 나누어진 형식이고 또 다른 하나는 아예 정수로 표현된 형식입니다. 먼저 4개 파트로 나누어진 것부터 작성해보겠습니다. IP 주소는 문자열의 처음부터 끝까지 패턴에 일치해야 하므로 정규표현식을 이렇게 시작하겠습니다.
/^$/
각 파트에 적용되는 규칙은 같으나 파트는 4번 반복되며 각 파트 사이에는 구분점이 있습니다. 점이 각 파트 사이에 있는 것은 '문자열 끝 바로 앞이 아닌 점 또는 문자열 끝'으로 표현할 수 있습니다(4주차 Lookahead Assertion 참조).
/^(xxx(\.(?!$)|$)){4}$/
원한다면 조금 더 이해하기 쉬운 (\.(?=\d)|$)
규칙을 사용하여 '숫자 바로 앞에 있는 점 또는 문자열 끝'으로 표현할 수도 있습니다. (저는 1바이트가 작은 쪽을 택했습니다 ^^;)
이제 xxx 부분을 각 파트에 해당하는 규칙으로 바꾸면 됩니다.
각 파트는 다음과 같은 값을 사용할 수 있습니다.
- 16진수 형식 : 항상 0x로 시작하며 00부터 FF까지
- 10진수 형식 : 0부터 255까지
- 8진수 형식 : 항상 0으로 시작하며 377까지
각각의 형식에 맞추어 규칙을 작성하면 다음과 같습니다.
- 16진수 형식 :
0x[\dA-F]{2}
- 10진수 형식 :
1?\d{1,2}|2[0-4]\d|25[0-5]
- 8진수 형식 :
0[1-3]?[0-7]{1,2}
이제 각 규칙을 하나로 묶으면 다음과 같이 표현될 수 있습니다.
/^((0x[\dA-F]{2}|0[1-3]?[0-7]{1,3}|1?\d{1,2}|2[0-4]\d|25[0-5])(\.(?!$)|$)){4}$/
그 다음은 정수 형태로 표현된 부분을 다룰 차례입니다. 16진수나 8진수의 경우에는 숫자의 자리수가 일정하기 때문에 지금까지 작성한 내용을 이해하셨다면 무리없이 작성할 수 있을 것입니다. 10진수의 경우에는 숫자가 일정 범위를 넘지 않도록 범위를 일일이 제한해주는 수 밖에 없습니다. 결국 10진수에 대해서는 다음과 같이 별로 아름답지 못한(?) 정규표현식이 필요해집니다.
[1-3]?\d{1,9}|4[0-1]\d{8}|42[0-8]\d{7}|429[0-3]\d{6}|4294[1-8]\d{5}|42949[0-5]\d{4}|429496[0-6]\d{3}|4294967[0-1]\d{2}|42949672[1-8]\d|429496729[0-5]
이제 작성한 모든 정규표현식을 합치면 해답과 같은 정규식을 얻을 수 있습니다.
[/toggle]
[adsense]