▸C언어/기본함수 및 구현식

string.h_strtok_문자열 나누기 (구현식 포함)

코데방 2019. 12. 5.
728x90

[ strtok ]

  • 기준 문자열에 포함된 문자를 기준으로 나눠줌
  • 문자열 자체를 찾는게 아닌, 포함된 문자 하나하나가 기준이 됨
  • strtok(str, "#@!")로 썼을 때, '#'이 나오거나 '@'가 나오거나 '!'가 나오면 끊어줌
  • 끊고난 다음 위치를 기억하고 있다가 문자열 대신 NULL을 넘겨주면 그 위치부터 다시 시작
  • NULL이 아닌 새로운 문자열을 제공해주면 리셋
  • 검색된 기준 문자는 '\0'로 바꿔줌 (원본이 훼손됨)
  • 시작위치부터 구분자가 연속으로 나올 경우 무시하고 지나감 (####과 같이)
  • 문자열의 끝에 도달하면 NULL값 반환
#include <stdio.h>
#include <string.h>

int main()
{
	char str[] = "abc#def@@#@ !g";
	
	char* ptr = strtok(str, "#@!");
	printf("%s\n", ptr);		// "abc"

	ptr = strtok(NULL, "#@!");
	printf("%s\n", ptr);		// "def"

	ptr = strtok(NULL, "#@!");
	printf("%s\n", ptr);		// " "

	ptr = strtok(NULL, "#@!");
	printf("%s\n", ptr);		// "g"

	ptr = strtok(NULL, "#@!");
	printf("%s\n", ptr);		// (null)
}

 


 

구현식은 아래와 같습니다. 실제 코드는 아니고 직접 짜본 코드입니다. strtok는 한 번 실행되면 계속 마지막 기준점을 저장하고 있으므로 정적변수(static)를 사용합니다.

 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char* my_strtok(char* str, char* find);

int main()
{
	/* 기본 strtok */
	char str[] = "abc#def@@#@ !g";

	char* ptr = strtok(str, "#@!");
	printf("%s\n", ptr);		// "abc"
	ptr = strtok(NULL, "#@!");
	printf("%s\n", ptr);		// "def"
	ptr = strtok(NULL, "#@!");
	printf("%s\n", ptr);		// " "
	ptr = strtok(NULL, "#@!");
	printf("%s\n", ptr);		// "g"
	ptr = strtok(NULL, "#@!");
	printf("%s\n", ptr);		// (null)

	printf("\n↓ 새로 만든 함수 ↓ \n");
	
	/* 새로 만든 my_strtok */
	char str2[] = "abc#def@@#@ !g";
	
	char* ptr2 = my_strtok(str2, "#@!");
	printf("%s\n", ptr2);		// "abc"
	ptr2 = my_strtok(NULL, "#@!");
	printf("%s\n", ptr2);		// "def"
	ptr2 = my_strtok(NULL, "#@!");
	printf("%s\n", ptr2);		// " "
	ptr2 = my_strtok(NULL, "#@!");
	printf("%s\n", ptr2);		// "g"
	ptr2 = my_strtok(NULL, "#@!");
	printf("%s\n", ptr2);		// (null)
}



char* my_strtok(char* str, char* find)
{
	static char* startPoint = NULL;		// 리턴해줄 위치
	static char* tokPoint = NULL;		// 다음 검색 시작점 위치

	// 원본 문자열 새로 들어오면 처음 위치로 초기화
	if (str != NULL) {
		startPoint = str;
		tokPoint = str;
	}

	// 원본 문자열이 없을 경우 시작 위치를 이전 실행에서 저장된 tokPoint위치로 옮겨줌
	else 
		startPoint = tokPoint;

	int findNum = strlen(find);
	int strNum = strlen(startPoint);
	
	// 원본 문자열에 남아 있는 문자가 없을 때 NULL값 반환
	if (strNum == 0)
		return NULL;
	// 찾을 문자열이 없을 때 startPoint 그대로 반환
	else if (findNum == 0)
		return startPoint;

	// 찾을 문자열 길이로 배열 생성해서 기준 문자들을 하나씩 넣어줌
	char* list;
	if ((list = (char*)malloc(sizeof(char) * findNum)) == NULL)
		return NULL;
	for (int i = 0; i < findNum; i++)
		list[i] = find[i];

	// 구분자 찾기
	int w = 0, status1 = 0, status2 = 0, i;
	for (i = 0; startPoint[i] != '\0'; i++) {
		
		// 한글자씩 비교
		for (int j = 0; j < findNum; j++) 
			// 같은 값을 찾았을 경우
			if (startPoint[i] == list[j]) {
				status1 = 1;	// 찾았음을 표시하고 break;
				break;
			}

		// 찾았는데 처음 값부터 일치했을 경우는 무시하고 넘어감
		if (status1 == 1 && status2 == 0) {
			status1 = 0;
			continue;
		}

		// 못찾고 넘어왔을 경우
		else if (status1 == 0 && status2 == 0) {
			status2 = 1;	// 하나라도 구분자 사이에 값이 있으므로 상태값 변경
			w = i;			// startPoint의 위치가 바껴야 하므로 첫 값 위치 저장
			continue;
		}

		// 사이에 값이 있으면서 구분자를 찾았을 경우 break
		else if (status1 == 1 && status2 == 1) {
			break;
		}
	}
	
	// 문자열 마지막이라면 찾은 위치를 tokPoint로 지정 (다음번 시작 위치)
	if (startPoint[i] == '\0')
		tokPoint = &startPoint[i];
	
	// 마지막이 아니라면 찾은 위치 다음을 tokPoint로 지정 (다음번 시작 위치)
	else {
		tokPoint = &startPoint[i + 1];
		startPoint[i] = '\0';	// 찾은 문자를 '\0'로 변경
	}
							
	// 다 쓴 리스트 메모리 제거
	free(list);
	
	// 연속된 구분자를 지나왔을 수 있으므로 구분자 이후 첫 값(w)을 시작 위치로 잡아서 리턴
	return startPoint = &startPoint[w];	
}
728x90

댓글

💲 추천 글