문자열 안에서 pat 이라는 문자열이 있는지 찾는 함수는 strstr이였습니다. wandbox에서는 생각보다 빠르게 그 함수가 동작하는데, 그 이유는 언젠가 한 번 문자열 알고리즘을 하면서 뜯어 본다고 했었어요. 사실 벌써부터 쉽지 않을 거 같은 예감이 드네요.

 

 오늘은 문자열 안에 어떠한 문자가 있는지를 판단하는 함수를 배워볼 건데요. 그 함수는 strchr입니다. 원형을 봅시다.

 

 

 char *strchr(const char *str,int ch);

 

 

 char형 포인터를 리턴합니다. str이라는 문자 열에서, ch가 나타나는 최초의 위치를 리턴합니다. 만약에 나타나지 않는다면 NULL 값을 리턴해요. 어렵지 않아요.

 
 

 예를 들어 문자열 str이 "chogahui05"가 있었다고 해 봅시다. 그러면 여기서, 'h'라는 문자열을 찾으려고 해요. char str[30] = "chogahui05"였다고 해 보고요. strchr(str,'h'); 를 호출하면 어떤 값이 리턴될까요?

 

 

 문자열 str이 이렇게 있어요. 문자 'h'는 2군데에서 나타납니다.

 

 

 이 중, str부터 선형 탐색을 했을 때, 'h'가 나오는 최초의 위치는 &(str[1])입니다. 고로, 제가 아래 그림에서 표시한 pos가 리턴이 될 거에요. 이 부분 크게 어렵지 않으실 거에요.

 

 

 그러면, strchr(str+3,'h')의 리턴값은 어떻게 될까요? 일단, str+3은 노란색 원소를 가리킬 거에요. 'g'입니다.

 

 

 그러면 노란색 부분을 탐색할 건데요. 이 중에서, 'h'가 처음으로 나타난 위치는 초록색으로 표시한 부분입니다. 이것을 pat으로 표시할 게요.

 

 

 그러면, strchr(str+3,'h')의 리턴값은 &(str[5])가 될 거에요. 실제로 제가 생각한 것이 맞는지 예제 프로그램을 실행시켜 봅시다. string은 "chogahui05"입니다. 이 문자열에서 h는 딱 2번 나옵니다.

 

 

저는 문제의 함수를 2번 호출했어요. 하나는 str부터, 그러니까 "chogahui05"에서 최초로 나타나는 h의 위치를 찾아서, 그 위치부터 NULL 문자를 만날 때 까지 출력을 해 주었습니다. 그리고, 2번째 것은 "gahui05"에서 최초로 나타나는 h의 위치를 찾아서 거기서부터 NULL을 만날 때 까지 출력을 해 주었어요. 그러면 처음 결과는 "hogahui05"가 나올 거에요. 2번째는 "hui05"가 나올 거에요.

 

 

 여기까지 이해가 되신다면 조금 더 심화된 예제를 보도록 하겠습니다.

 

 


 티스토리 스킨 편집에 보면 HTML 편집기가 있습니다. 거기에는 수많은 태그들이 있는데, 예를 들어서 <body>라던지, </p>와 같은 것들이 그러한 예입니다. 물론 <tag/>는 아무런 역할도 하지 않아요. 우리는 <를 만났을 때, 태그를 뽑아내 볼 겁니다. 어떻게 하면 좋을까요? 간단하게 어떻게 코딩을 할 지 생각해 봅시다.

 

 먼저 <를 만났을 때, tag를 뽑기 위해서 제일 먼저 해야 할 일은, >를 찾는 것입니다.

 

 

 만약에 str[pos]에 '<'이 저장되어있다고 한다면, strchr(str+pos,'>')를 호출하면 될 겁니다. 실제로 이 위치를 찾은 다음에 str을 빼면, str의 몇 번째 위치에 >가 나타나는지 알 수 있어요. 이 위치를 lo라고 합시다. 그러면, 우리는 str+pos + 1부터 str + lo - 1까지의 부분 문자열을 뽑아야 합니다.

 

 java는 substring이 있긴 합니다만, c는 없네요. 그러면 직접 뽑아야 겠군요. 초록색 부분에서, 맨 끝 부분에 '/'가 나온다면 아무런 역할도 하지 않습니다. 이 때에는 따로 부분 문자열을 뽑을 필요조차 없어요. 단지, 보라색 부분이 유효한지만 검사하면 됩니다. 유효하다는 소리는 tag로 나올 수 있는 문자들만 나오느냐를 보는 겁니다.

 

 

 

 앞에 '/'가 나오면, str+pos+2부터 str+lo-1까지를 뽑으면 될 겁니다.

 

 

 만약에 앞과 뒤에 '/'가 없다면 어떨까요?

 

 

 초록색 부분에서 뽑으면 됩니다. 여는 태그로요. 우리가 최종적으로 뽑은 문자열이 tag로 나올 수 있는 것들이라면 그대로 뽑으면 되고, 아니면 invaild 합니다. 의외로 파싱 문제라던지, 문자열 처리에서 생각보다 자주 쓰이는 함수이니 알아두시면 좋을 듯 싶습니다.