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

libc 문자열 조작 함수 정리 (part 07 - strspn, strcspn)

Language/C & C++
2018. 8. 20. 20:53

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 VII. strspn, strcspn


본 포스팅에서는 전체 문자열 중에서 특정 범위의 문자로만 구성된 부분 문자열span을 구하는 함수인 strspnstrcspn 함수에 대해 정리한다.

<Prologue>


strspn은 문자열을 첫 글자부터 끝 글자까지 하나씩 탐색해 나가다가 미리 지정한 문자 외의 다른 문자를 만나면 지금까지 센 문자수를 반환하고 종료하는 기능을 한다. 즉 특정 범위의 문자로만 구성된 부분 문자열의 길이를 얻는 기능을 수행한다. 반대로 strcspn는 문자열을 첫 글자부터 끝 글자까지 하나씩 탐색해 나가다가 특정 범위의 문자로만 구성된 부분 문자열을 만났을 경우 그 위치를 반환한다.

1. strspn

strspn의 원형은 다음과 같다.

size_t strspn(const char * str1, const char * str2);
str1
검색 대상이 되는 문자열이다.
str2
문자들을 열거하는 패턴pattern이다.

반환 값은 size_t 형으로서, 맨 처음 문자부터 시작하여 str2에서 지정한 패턴을 벗어나지 않는 부분 문자열의 길이를 반환한다. 패턴에 맞는 부분 문자열이 처음부터 없다면 0을 반환한다.

예를 들어, 문장의 첫 부분에 금액이 적혀있는 경우 이를 인식하여 따로 보관하고자 한다. 금액은 '0'부터 '9'까지의 숫자 문자와 '.', ',', $ 기호로 구성되어 있기 때문에 이 범위를 벗어난 부분 문자열이 나타날때까지 문장의 첫 글자부터 세어 나가게 한다.

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

int main(int argc, char * argv[])
{
	char str1[64] = "$1,823.55 is paid to purchase this product.";
	char str2[64] = { '\0', };
	char pattern[64] = "1234567890$,.";
	size_t result = 0;

	printf("original text: %s\n", str1);

	result = strspn(str1, pattern);

	if (result > 0)
	{
		strncpy(str2, str1, result);
		printf("currency data found: \"%s\"\n", str2);
	}
	else
	{
		printf("currency data not found.\n");
	}

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

위 코드를 참조하면, result = strspn(str1, pattern);에 의해 문자열의 맨 처음 문자로부터 주어진 패턴("123456789$,.")을 만족하는 부분 문자열의 길이를 얻는다. 이 값은 result 변수에 보관되며 구체적으로 9의 값("$1,823.55"의 총 9 문자)이 보관된다.

이 값은 strncpy 함수에서 사용된다. strncpy(str2, str1, result);에 의해 str1의 처음 9 문자가 str2에 복사된다. 즉, 해당 패턴을 만족하는 부분 문자열이 별도의 버퍼에 복사된 것이다. 이를 그 다음 줄인 printf 함수에서 출력하는 방식으로 본 예제는 작동한다.

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


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

size_t wcsspn(const wchar_t * str1, const wchar_t * str2);

2. strcspn


strcspn은 지정된 패턴을 만족하지 않는 부분 문자열의 길이를 구할 때 사용한다. 원형은 다음과 같다.

size_t strcspn(const char * str1, const char * str2);
str1
검색 대상이 되는 문자열이다.
str2
문자들을 열거하는 패턴pattern이다.

실행 결과 패턴을 만족하지 않는 부분 문자열의 길이, 다시 말하면 패턴을 만족하는 부분 문자열이 시작하는 위치를 반환한다. 만일 str1에는 str2에서 지정한 패턴에 맞는 부분 문자열이 없을 경우 str1의 길이를 반환한다.

상기 예제 코드에서 문자열을 수정하였다. 금액 관련한 표현이 문자열의 처음에 등장하지 않을 경우 해당 위치를 찾을 때 본 함수를 활용 가능하다.

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

int main(int argc, char * argv[])
{
	char str1[64] = "Totol expense: $1,234.56 will be paid.";
	char str2[64] = { '\0', };
	char pattern[64] = "1234567890$,.";
	size_t result = 0;
	size_t count = 0;

	printf("original text: \"%s\"\n", str1);

	result = strcspn(str1, pattern);
	if (result > 0)
	{
		printf("currency data found at %zu(th) position.\n", result);
		
		count = strspn((str1 + result), pattern);
		if (count > 0)
		{
			strncpy(str2, (str1 + result), count);
			printf("currency data found: \"%s\"\n", str2);
		}
		else
		{
			printf("unexpected error.\n");
		}
	}
	else
	{
		printf("currency data not found.\n");
	}
	return 0;
}
[그림 1] strcspn.c 예제 소스 코드
[그림 2] strcspn.c 예제 소스 코드의 실행 결과

위 소스 코드를 참조하면, 찾고자 하는 패턴("1234567890$,.")의 숫자 문자열이 문장의 중간에 위치해 있는데 정확히 몇 번째 문자부터 시작하는지를 확인하기 위하여 strcspn을 사용한다. 이 함수는 해당 패턴이 만족하지 않는 부분 문자열의 길이를 반환하는데 이는 곧 해당 패턴이 만족하는 영역의 시작 위치이므로, result 변수에 보관한다. 구체적으로 이 값은 15, 즉 15번째 문자부터 해당 패턴을 만족하는 부분 문자열이 존재함을 알린다. (주의: C 언어는 맨 처음 문자를 0 번째로 본다.)

if 문의 조건(result > 0)을 만족하므로 상기 설명한 strspn 함수를 사용하여 검출하고자 하는 부분 문자열의 길이를 구한다. 이 때 매개변수로 전달되는 문자열 포인터는 str1 = &str[0]이 아니라 (str1 + result) = &str[15]임을 확인한다. strspn은 문자열의 중간에서 부분 문자열을 복사하는 기능이 없으므로 strcspn에서 구한 위치와 원본 문자열을 포인터 연산하여 해당 부분 문자열이 strspn의 입장에서 가장 처음에 오도록 전달하는 것이다.

패턴에 맞는 부분 문자열의 시작 위치를 strcspn을 통해 알고 있고 그 부분 문자열의 길이를 strspn을 통해 알았다면 복사만 하면 된다. 부분 문자열의 복사는 strncpy로 수행하는데 역시 복사 대상 문자열은 (str1 + result) = &str[15]으로 전달되었음을 확인한다.

2-1. Wide Character 확장 함수 - wcscspn


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

size_t wcscspn(const wchar_t * str1, const wchar_t * str2);

<Epilogue>


본 포스팅을 통해 문자열 복사 함수에 대해 정리해 보았다. 다음 포스팅[libc 문자열 조작 함수 정리 (part 08 - strlen)]에서는 문자열의 길이를 구하는 함수인 strlen 함수에 대해 정리한다.

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