^(코딩캣)^ = @"코딩"하는 고양이;

libc 문자열 조작 함수 정리 (part 06 - strtok)

Language/C & C++
2018. 8. 20. 19:14

libc 문자열 조작 함수 정리


C 언어에서 문자열 처리는 복잡하다. 언어 수준에서 문자열이라는 데이터 형 자체를 지원하지도 않으니, 덧셈 기호(+)나 비교연산자(==)와 같은 기호를 사용하는 직관적인 문자열 연산을 사용할 수 없기 때문이다. C 언어가 문자열 데이터 형을 지원하지 않고, 문자열을 다루는 연산자도 없으니 모든 문자열 연산은 문자열 함수를 통해 이루어진다. C 표준 라이브러리(일명 'libc')에서 str...로 시작하는 함수들이 그것이며, 모두 string.h 헤더(C++은 cstring 헤더)에 정의되어 있으며 본 시리즈를 통해 이들 함수의 사용법을 정리해보고자 한다. 본 시리즈는 cplusplus(http://www.cplusplus.com) 및 MSDN에 나와있는 레퍼런스를 기준으로 하여 작성되었다.

  1. libc 문자열 조작 함수 정리 (part 01 - strcpy, strncpy)
  2. libc 문자열 조작 함수 정리 (part 02 - strcat, strncat)
  3. libc 문자열 조작 함수 정리 (part 03 - strcmp, strncmp)
  4. libc 문자열 조작 함수 정리 (part 04 - strchr, strrchr)
  5. libc 문자열 조작 함수 정리 (part 05 - strstr)
  6. libc 문자열 조작 함수 정리 (part 06 - strtok)
  7. libc 문자열 조작 함수 정리 (part 07 - strspn, strcspn)
  8. libc 문자열 조작 함수 정리 (part 08 - strlen)
  9. libc 문자열 조작 함수 정리 (part 09 - strpbrk)
  10. libc 문자열 조작 함수 정리 (part 10 - strxfrm, strcoll)
  11. libc 문자열 조작 함수 정리 (part 11 - strerror)

Part VI. strtok


본 포스팅에서는 특정 기호를 기준으로 문자열 분할tokenization을 지원하는 함수인 strtok 계열의 함수에 대해 사용 예를 정리한다.

<Prologue>


strtok은 지정된 문자를 기준으로 문자열을 자르는 역할을 한다. 예를 들어 문자열 중에 ';' 문자가 있다면 그 문자 직전까지를 하나의 문자열로 보고, 그 문자 직후부터를 또 하나의 문자열로 취급한다는 뜻이다. 이 때 strtok 함수는 해당 문자열에서 ';' 문자가 있던 자리를 NULL 문자로 치환해버린다. 즉 원본 문자열의 내용이 변한다는 것이다.

구체적으로 "Rachel;Tom;John;Michael;Jude"라는 문자열에 대해 strtok 함수를 사용하여 ';' 문자를 기준으로 분할을 수행할 때 "Rachel", "Tom", "John", "Michael", "Jude"라는 5개의 부분 문자열을 얻는데, 이 과정에서 원본 문자열은 "Rachel\0Tom\0John\0Michael\0Jude"와 같이 원래 있던 ';' 문자가 NULL 문자로 변경된다.

1. strtok


strtok 함수의 원형은 다음과 같다.

char * strtok(char * str, const char * delimiters);
str
분할할 문자열이다. 내용이 변할 것이므로 const가 붙지 않는다. 즉 문자열 상수는 받을 수 없고 버퍼만 받을 수 있다.
deliminiters
분할의 기준이 되는 문자이다. 문자열로 입력받기 때문에 기준 문자를 여러개 지정할 수 있다. 그 중 하나라도 분할할 문자열에 있다면 그 문자를 NULL 문자로 고치면서 부분 문자열을 반환한다.

str의 문자열에서 deliminiters에 해당하는 문자가 발견되면 그 자리를 NULL 문자로 치환하고 부분 문자열을 반환한다. 문자열의 끝에 도달하였거나 분할할 것이 없다면 NULL을 반환한다.

/* strtok.c */
#include <stdio.h>
#include <string.h>

int main(int argc, char * argv[])
{
	char str1[64] = "name=Tom;social=facebook,twitter,instagram";
	char str2[64] = "=;,";
	char * result = NULL;
	char * temporary = NULL;

	printf("<BEFORE>\n");
	printf("str1 = \"%s\";\n", str1);

	printf("<STRTOK>\n");
	result = strtok(str1, str2);
	printf("strtok(str1, \"%s\") = \"%s\";\n", str2, result);
	while (result != NULL)
	{
		result = strtok(NULL, str2);

		if (result == NULL)
			printf("strtok(NULL, \"%s\") = NULL;\n", str2);
		else
			printf("strtok(NULL, \"%s\") = \"%s\";\n", str2, result);
	}

	printf("<AFTER>\n");
	printf("str1 = \"%s\";\n", str1);

	return 0;
}
[그림 1] strtok.c 예제 소스 코드
[그림 2] strstr.c 예제 소스 코드의 실행 결과

위 코드는 "name=Tom;social=facebook,twitter,instagram"의 문자열을 strtok 함수로 분할하는 예이다. 해당 문자열은 세미콜론(';')과 등호('=') 및 컴마(',')로 단어들을 분리해낼 수 있음을 직관적으로 알 수 있다. C 언어로 이를 분리하기 위하여 deliminiters 매개변수에 세 기호들이 열거된 문자열을 전달한다.

분리 대상이 되는 문자열은 result = strtok(str1, str2);로서 최초 1회만 매개변수로 전달되고 그 이후 호출에서는 result = strtok(NULL, str2);와 같이 전달하지 않는다. 이미 대산 문자열을 한 번 분할했기 때문에 strtok 함수는 내부적으로 가장 마지막으로 분할한 위치를 기억하고 있기 때문이다. 만일 함수 호출 실행시마다 첫 번째 매개변수에 대상 문자열을 전달하면 분할 작업을 가장 첫 문자부터 시작하므로 최초로 분할되어 나온 부분 문자열만 반복하여 얻어질 것이다.

검색할 문자열의 끝에 도달하였거나 문자열에 분할 기준의 문자가 없어서 더 이상 분할될 수 없을 경우에는 NULL을 반환한다. 루프를 수행중이었다면 이 시점에 루프를 종료하면 된다.

1-1. Wide Character 확장 함수 - wcstok


상기 strtok는 ASCII 문자열 또는 UTF-8 인코딩의 Unicode 문자열에 대해 사용 가능하다. UTF-16/UTF-32와 같은 Wide Character 문자열의 'tokenization'은 아래의 함수를 사용 가능하며, wchar.h, C++에서는 cwchar 헤더를 include한다.

wchar_t * wcstok(wchar_t * wcs, const wchar_t * delimiters);

<Epilogue>


본 포스팅을 통해 문자열 복사 함수에 대해 정리해 보았다. 다음 포스팅[libc 문자열 조작 함수 정리 (part 07 - strspn, strcspn)]에서는 패턴에 맞는 부분 문자열을 검색하는 함수인 strspn, strcspn 함수에 대해 정리한다.

카테고리 “Language/C & C++”
more...