glibc에서 기본으로 지원하는 regex를 사용해 특정 문자열을 잡아내야 하는데 몇 개가 먹히지 않았다.
1. 국내주소
[\S]+(도|시|북|남)\s[\S]+(구|군|시)\s[\S]+(면|동|구|군|로).*
2. 일반전화
(070|02|031|032|033|041|042|043|051|052|053|054|055|061|062|063|064)[-.\|_\ ]?(\\d{3,4})[-.\|_\ ]?(\\d{4})
정규식 검사 홈페이지에선 잘 동작했으나....
정작 코드에선 안 됐다.
(테스트 코드라 막 짰음. 아래의 regexOldPhone과 regexAddr이 실제 사용되고 있는 정규식)
char test[128] = { 0, };
char test2[128] = { 0, };
char test3[128] = { 0, };
snprintf(test, sizeof(test), "02-1234-1345");
snprintf(test2, sizeof(test2), "041-8167-2610");
snprintf(test3, sizeof(test3), "서울특별시 도봉구 창동 659-29 삼성쉐르빌오피스텔 804호");
std::string regexOldPhone="(070|02|031|032|033|041|042|043|051|052|053|054|055|061|062|063|064)[-.\|_\ ]?(\\d{3,4})[-.\|_\ ]?(\\d{4})";
std::string regexNewPhone="(070|02|031|032|033|041|042|043|051|052|053|054|055|061|062|063|064)[-.\|_\ ]?([[:digit:]]{3,4})[-.\|_\ ]?([[:digit:]]+{4})";
std::string regexAddr="[\S]+(도|시|북|남)\s[\S]+(구|군|시)\s[\S]+(면|동|구|군|로).*";
int cflags = REG_EXTENDED;
int cflags2 = REG_EXTENDED;
int cflags3 = REG_EXTENDED;
regex_t reg;
regex_t reg2;
regex_t reg3;
// reg compile
int ret = regcomp(®, regexOldPhone.c_str(), cflags);
int ret2 = regcomp(®2, regexNewPhone.c_str(), cflags2);
int ret3 = regcomp(®3, regexAddr.c_str(), cflags3);
if (ret != 0) {
char errStr[128];
regerror(ret, ®, errStr, sizeof(errStr));
printf("regcomp error(%s)\n", errStr);
exit(1);
}
if (ret2 != 0) {
char errStr[128];
regerror(ret2, ®2, errStr, sizeof(errStr));
printf("regcomp2 error(%s)\n", errStr);
exit(1);
}
if (ret2 != 0) {
char errStr[128];
regerror(ret2, ®2, errStr, sizeof(errStr));
printf("regcomp3 error(%s)\n", errStr);
exit(1);
}
int eflags = 0, len;
int offset = 0, cnt = 1;
// pattern matching
if ((ret = regexec(®, test, 0, NULL, 0))== 0)
{
printf("matched string(%s)\n",test);
cnt++;
}
regfree(®);
eflags = 0; len=0;
offset = 0, cnt = 1;
ret=0;
if ((ret = regexec(®2, test2, 0, NULL, 0))== 0)
{
printf("matched string2(%s)\n",test2);
cnt++;
}
regfree(®2);
eflags = 0; len=0;
offset = 0, cnt = 1;
ret=0;
if ((ret = regexec(®3, test3, 0, NULL, 0))== 0)
{
printf("matched string3(%s)\n",test3);
cnt++;
}
regfree(®3);
조사하면서 알게 된 것.
1) 우리가 흔히 아는 정규식의 Character Class(문자 클래스)는 POSIX 정규식의 문자 클래스와 다르다. 즉, \d, \S, \s는 glibc의 regex 라이브러리에서 사용될 수 없다.
https://www.regular-expressions.info/posixbrackets.html
2) glibc의 정규식은 POSIX 인터페이스를 따른다.
https://www.gnu.org/software/libc/manual/html_node/Regular-Expressions.html#Regular-Expressions
The GNU C Library supports two interfaces for matching regular expressions. One is the standard POSIX.2 interface, and the other is what the GNU C Library...
-------------------------
확인 결과 정규식의 문제가 아니라 제품 내 코드 문제였다.
string 토큰화를 하는 과정에서 ':'를 토큰으로 사용하면서 POSIX 문자 클래스까지 같이 잘려버린 것....
그래도 문자 클래스를 사용할 때 주의해야 한다는 건 알았으니 소득이 영 없는 것도 아니다.
'Develop > C, C++' 카테고리의 다른 글
[C/C++] explicit 키워드란? (2) | 2021.09.17 |
---|