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})

 

정규식 검사 홈페이지에선 잘 동작했으나....

https://regexr.com/

불러오는 중입니다...

 

정작 코드에선 안 됐다.

(테스트 코드라 막 짰음. 아래의 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(&reg, regexOldPhone.c_str(), cflags);
int ret2 = regcomp(&reg2, regexNewPhone.c_str(), cflags2);
int ret3 = regcomp(&reg3, regexAddr.c_str(), cflags3);

if (ret != 0) {
	char errStr[128];
	regerror(ret, &reg, errStr, sizeof(errStr));
	printf("regcomp error(%s)\n", errStr);
	exit(1);
}

if (ret2 != 0) {
	char errStr[128];
	regerror(ret2, &reg2, errStr, sizeof(errStr));
	printf("regcomp2 error(%s)\n", errStr);
	exit(1);
}

if (ret2 != 0) {
	char errStr[128];
	regerror(ret2, &reg2, 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(&reg, test, 0, NULL, 0))== 0)
{
	printf("matched string(%s)\n",test);
	cnt++;
}
regfree(&reg);

eflags = 0; len=0;
offset = 0, cnt = 1;
ret=0;

if ((ret = regexec(&reg2, test2, 0, NULL, 0))== 0)
{
	printf("matched string2(%s)\n",test2);
	cnt++;
}
regfree(&reg2);

eflags = 0; len=0;
offset = 0, cnt = 1;
ret=0;

if ((ret = regexec(&reg3, test3, 0, NULL, 0))== 0)
{
	printf("matched string3(%s)\n",test3);
	cnt++;
}
regfree(&reg3);

 

조사하면서 알게 된 것.

 

1) 우리가 흔히 아는 정규식의 Character Class(문자 클래스)는 POSIX 정규식의 문자 클래스와 다르다. 즉, \d, \S, \s는 glibc의 regex 라이브러리에서 사용될 수 없다.

https://www.regular-expressions.info/posixbrackets.html

https://zetawiki.com/wiki/%EC%A0%95%EA%B7%9C%ED%91%9C%ED%98%84%EC%8B%9D_%EB%AC%B8%EC%9E%90_%ED%81%B4%EB%9E%98%EC%8A%A4

 

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