- 1 1. 서론
- 2 2. C-gengo의 문자열이란? 기본 개념과 종료 문자 중요성
- 3 3. C 언어에서 부분 문자열을 잘라내는 방법【표준 라이브러리 편】
- 4 4. C-gengo에서 부분 문자열을 추출하는 방법【자작 함수 편】
- 5 5. 문자코드별 문자열 추출 방법
- 6 6. C언어에서 문자열을 분할하는 방법
- 7 7. 응용 예: 특정 문자 앞뒤를 추출하는 방법
- 8 8. 요약
1. 서론
C 언어에서 문자열을 다루는 것은 프로그래밍을 배우는 데 있어 중요한 기술 중 하나입니다. 특히、문자열 추출(부분 문자열 추출)은 데이터 처리 및 포맷 변환을 할 때 자주 사용됩니다.
본 기사에서는、C 언어에서 문자열을 추출하는 방법에 대해、표준 라이브러리 함수를 사용하는 방법, 직접 함수를 만드는 방법, 멀티바이트 문자(일본어) 대응, 문자열 분할 방법 등을 자세히 설명합니다. 또한、응용 예시와 오류 처리에 대해서도 소개하니 꼭 마지막까지 확인해 주세요.
이 기사에서 배울 수 있는 것
본 기사를 읽음으로써 다음과 같은 스킬을 습득할 수 있습니다.
- C 언어 문자열의 기본 개념과 종료 문자 의 역할
strncpy
strchr
표준 라이브러리 함수 를 사용한 부분 문자열 추출- 자작 함수
- 멀티바이트 문자(일본어)를 고려한
strtok
문자열 분할 방법- 특정 문자의 앞뒤를 가져오는 방법
초보자도 이해하기 쉽도록 코드 예제를 곁들여 설명합니다.
왜 C 언어에서 문자열 추출이 중요한가?
C 언어는문자열을「배열(char형 배열)」으로 취급하기 때문에、다른 고급 언어(Python이나 JavaScript 등)처럼 쉽게 부분 문자열을 얻을 수 없습니다. 따라서、아래와 같은 상황에서 적절한 방법을 선택하는 것이 중요합니다.
1. 입력 데이터 처리
예를 들어、로그 데이터나 CSV 파일 등의 데이터를 분석할 때 특정 항목을 추출해야 합니다.
2. 특정 키워드 검색
문자열 중에서 특정 키워드를 찾아 그 전후 정보를 얻는 것은 검색 기능 및 데이터 추출에 필수적입니다.
3. 프로그램 안전성 향상
strncpy
와 같은 함수를 적절히 사용함으로써、버퍼 오버플로우(버퍼 크기를 초과하는 데이터 쓰기)을 방지할 수 있습니다. 이는、보안상의 위험을 회피하기 위해 중요합니다.
본 기사 구성
본 기사에서는 아래 흐름으로 설명을 진행합니다.
- C 언어의 문자열이란? 기본 개념과 종결 문자의 중요성
- C 언어로 부분 문자열을 추출하는 방법【표준 라이브러리 편】
- C 언어에서 부분 문자열을 추출하는 방법【자작 함수 편】
- 문자 코드별 문자열 추출 방법
- C 언어로 문자열을 분할하는 방법
- 응용 예: 특정 문자의 앞뒤를 추출하는 방법
- 요약
- FAQ
그럼, 먼저「C 언어의 문자열이란? 기본 개념과 종단 문자(널 문자)의 중요성」에 대해 자세히 살펴보겠습니다.
2. C-gengo의 문자열이란? 기본 개념과 종료 문자 중요성
2.1 C-gengo의 문자열 기본 개념
문자열은 “char의 배열”
C-gengo에서는, 문자열을 문자의 배열(char형 배열)으로 취급합니다. 예를 들어, 아래 코드는 문자열 정의와 표시의 기본적인 예시입니다。
#include <stdio.h>
int main() {
char str[] = "Hello, World!"; // Define a string literal as an array
printf("%s ", str); // Output the string
return 0;
}
이 코드에서는, "Hello, World!"
라는 문자열이 char
형 배열로 저장되고, printf("%s\n", str);
에 의해 출력됩니다。
문자열의 내부 구조
문자열 "Hello"
은, 메모리 상에서 다음과 같이 저장됩니다。
인덱스 | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
문자 | H | e | l | l | o | \0 |
C-gengo에서는, 문자열의 종료를 나타내는 특수 문자(널 문자 '\0'
)가 마지막에 자동으로 추가되기 때문에, 문자열 길이는 “실제 문자 수 + 1”이 됩니다。
2.2 종료 문자(널 문자 '널 문자란?
'
)의 중요성
널 문자란?
'널 문자가 없을 경우의 문제
널 문자('\0'
)는, 문자열의 끝을 나타내는 특수 문자입니다. C-gengo의 문자열을 올바르게 다루기 위해서는, 이 널 문자의 존재를 이해하고 있어야 합니다。
#include <stdio.h>
int main() {
char str[6] = {'H', 'e', 'l', 'l', 'o', '\0'}; // Explicitly specify the null terminator
printf("%s ", str); // Display correctly
return 0;
}
위의 코드에서는, '\0'
가 없으면 "Hello"
의 종료가 인식되지 않아, 예기치 않은 동작이 발생할 가능성이 있습니다。
2.3 문자열의 올바른 정의 방법
아래와 같이, 종료 문자를 잊어버리면, 메모리의 비정상적인 동작을 일으킬 가능성이 있습니다。
#include <stdio.h>
int main() {
char str[5] = {'H', 'e', 'l', 'l', 'o'}; // Does not include the null terminator
printf("%s ", str); // May cause unexpected behavior
return 0;
}
오류의 원인
printf("%s\n", str);
null 문자'\0'
을 찾을 때까지 문자를 출력하고 계속합니다- 만약 가 없으면, 메모리 상의 다른 데이터가 출력될 가능성이 있다。
방법① 문자열 리터럴 사용하기
방법② 명시적으로 배열 정의하기
가장 일반적인 문자열 정의 방법은, 문자열 리터럴을 사용하는 것입니다。
char str[] = "Hello";
이 방법에서는, C 컴파일러가 자동으로 널 문자 '\0'
를 추가해 주기 때문에, 별도의 처리는 필요 없습니다。
2.4 문자열 크기 확인 방법
수동으로 '\0'
를 포함하여 정의하는 경우는, 다음과 같이 기술합니다。
char str[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
- 문자수 의 크기를 지정하고, 마지막에 를 넣는 것이 중요합니다。
- 만약 에 를 넣는 것을 깜빡하면, 예기치 않은 동작이 발생합니다。
strlen
의 동작
문자열의 길이(문자 수)를 얻기 위해서는, strlen
함수를 사용합니다。
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "Hello";
printf("Length of the string: %lu\n", strlen(str)); // Outputs 5 (does not include the null terminator)
return 0;
}
2.5 정리
strlen
널 문자'\0'
가 나타날 때까지의 문자 수를 셈합니다sizeof(str)
3. C 언어에서 부분 문자열을 잘라내는 방법【표준 라이브러리 편】
- C 언어의 문자열은
char
배열로 표현된다 - 종단 문자(널 문자
'\0'
)는 문자열의 끝을 나타내므로 반드시 포함해야 합니다 - 문자열의 길이를 얻으려면
strlen
를 사용합니다 - 적절한 방법으로 문자열을 정의하지 않으면 예기치 않은 오류가 발생할 가능성이 있습니다
3.1 strncpy
를 사용한 부분 문자열 가져오기
C 언어에서 부분 문자열을 잘라내려면, 표준 라이브러리를 활용하는 방법이 있습니다. 이 섹션에서는, strncpy
와 strchr
등 의 표준 라이브러리 함수 를 사용하여, 문자열을 부분적으로 가져오는 방법을 설명합니다.
strncpy
의 기본 구문
strncpy
는 문자열의 일부를 다른 버퍼에 복사하는 함수입니다.
기본 사용 예
char *strncpy(char *dest, const char *src, size_t n);
dest
src
n
'\0'
strncpy
의 주의점
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "Hello, World!";
char dest[6]; // Buffer to store the substring
strncpy(dest, src, 5); // Copy the first 5 characters "Hello"
dest[5] = '\0'; // Manually add the null terminator
printf("Substring: %s\n", dest); // Output "Hello"
return 0;
}
3.2 strncpy_s
를 사용한 안전한 문자열 복사
- NULL 문자
'\0'
를 수동으로 추가해야 합니다 는 최대 글자를 복사하지만, 때문에 명시적으로 를 추가해야 합니다。 - 버퍼 오버플로우에 주의 의 크기보다 가 크면, 버퍼를 초과하여 기록할 가능성이 있습니다。
strncpy_s
의 기본 구문
strncpy_s
는 strncpy
의 안전성을 강화한 버전으로, 버퍼 오버플로우를 방지할 수 있습니다.
사용 예
errno_t strncpy_s(char *dest, rsize_t destsz, const char *src, rsize_t n);
dest
destsz
dest
src
n
strncpy_s
의 장점
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "Hello, World!";
char dest[6];
if (strncpy_s(dest, sizeof(dest), src, 5) == 0) {
dest[5] = '\0'; // Add null terminator just in case
printf("Substring: %s\n", dest);
} else {
printf("Copy error\n");
}
return 0;
}
3.3 strchr
를 사용한 특정 문자까지의 잘라내기
- 버퍼 크기 () 를 지정하기 위해, 안전하게 복사할 수 있다。
destsz
n
하지만、strncpy_s
는 C11 규격에 추가되었기 때문에, 일부 환경에서는 사용할 수 없다는 점에 주의가 필요합니다。
strchr
의 기본 구문
strchr
를 사용하면, 특정 문자의 위치를 찾아, 그 부분까지의 문자열을 가져올 수 있습니다.
사용 예
char *strchr(const char *str, int c);
str
c
char
포인트
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "Hello, World!";
char *pos = strchr(str, ','); // Find the position of ','
if (pos != NULL) {
int length = pos - str; // Calculate the number of characters up to ','
char result[20];
strncpy(result, str, length);
result[length] = '\0'; // Add the null terminator
printf("Substring: %s\n", result); // Output "Hello"
}
return 0;
}
3.4 strstr
를 사용한 키워드 검색과 잘라내기
strchr
가장 먼저 발견된c
의 주소를 반환하므로,pos - str
strncpy
strstr
의 기본 구문
strstr
는 부분 문자열을 검색하고, 그 이후의 문자열을 가져오는 데 편리합니다.
사용 예
char *strstr(const char *haystack, const char *needle);
헤이스택
바늘
포인트
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "Hello, World!";
char *pos = strstr(str, "World"); // Search for the position of "World"
if (pos != NULL) {
printf("Found substring: %s\n", pos);
} else {
printf("Substring not found.\n");
}
return 0;
}
3.5 정리
strstr
needle
NULL
needle
haystack
4. C-gengo에서 부분 문자열을 추출하는 방법【자작 함수 편】
strncpy
를 사용하면, 부분 문자열을 안전하게 복사할 수 있지만, 널 문자를 수동으로 추가해야 합니다。strncpy_s
는destsz
를 지정할 수 있어 안전성이 향상됩니다.strchr
를 사용하면, 특정 문자까지의 부분 문자열을 얻을 수 있습니다.strstr
를 사용하면, 특정 키워드의 위치를 가져와서 그 이후를 잘라낼 수 있다.
표준 라이브러리를 활용함으로써, C 언어에서의 문자열 처리를 간단하면서도 안전하게 구현할 수 있습니다.
4.1 자작 함수를 만드는 장점
표준 라이브러리를 활용하면 기본적인 부분 문자열을 추출할 수 있지만, 경우에 따라보다 유연한 방법가 요구되는 경우가 있습니다. 따라서, 이 섹션에서는자작 함수를 사용한 부분 문자열 추출에 대해 설명합니다。
4.2 기본적인 부분 문자열 추출 함수
표준 라이브러리를 사용하면, 부분 문자열의 복사와 검색이 가능하지만, 다음과 같은 문제점이 있습니다。
strncpy
는 null 문자'\0'
을 자동으로 추가하지 않는다strchr
와strstr
는 부분적인 검색만 할 수 있다- 더 유연한 문자열 조작이 어렵다
그렇기 때문에, 특정 용도에 맞게 커스터마이즈할 수 있는자작 함수를 만드는 것이 유효합니다。
함수 사양
우선, 지정한 위치에서 문자열을 추출하는 기본적인 함수를 작성합니다。
구현 코드
- 인수
const char *source
int start
int length
char *dest
- 처리 내용
start
length
dest
'\0'
요점
#include <stdio.h>
#include <string.h>
void substring(const char *source, int start, int length, char *dest) {
int i;
for (i = 0; i < length && source[start + i] != '\0'; i++) {
dest[i] = source[start + i];
}
dest[i] = '\0'; // Add null terminator
}
int main() {
char text[] = "Hello, World!";
char result[10];
substring(text, 7, 5, result); // Extract "World"
printf("Substring: %s\n", result);
return 0;
}
4.3 malloc
을 사용한 동적 부분 문자열 획득
for
length
'\0'
dest[i] = '\0';
반드시 널 문자를 끝에 배치
함수 사양
위의 함수에서는, dest
의 크기를 사전에 확보할 필요가 있습니다. 그러나, 필요한 크기를 동적으로 확보할 수 있다면, 보다 범용적인 함수가 됩니다。
구현 코드
- 필요한 메모리를 로 확보
start
length
- 호출자에서 를 해야 한다
요점
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *substring_dynamic(const char *source, int start, int length) {
char *dest = (char *)malloc(length + 1); // +1 for the null terminator
if (dest == NULL) {
return NULL; // Memory allocation failed
}
int i;
for (i = 0; i < length && source[start + i] != '\0'; i++) {
dest[i] = source[start + i];
}
dest[i] = '\0';
return dest;
}
int main() {
char text[] = "Hello, World!";
char *result = substring_dynamic(text, 7, 5);
if (result != NULL) {
printf("Substring: %s\n", result);
free(result); // Free allocated memory
} else {
printf("Memory allocation failed.\n");
}
return 0;
}
4.4 멀티바이트 문자(Nihongo) 대응
malloc
동적으로 메모리를 할당하기 위해- 사용 후에는 에서 메모리를 해제해야 합니다.
멀티바이트 문자를 고려한 구현
Nihongo(UTF-8 등 멀티바이트 문자)를 다루는 경우, 1문자가 1바이트는 아닐 수도 있다 때문에, 단순한 substring
함수는 올바르게 동작하지 않습니다。
구현 코드(UTF-8 대응)
mbstowcs
wchar_t
wcsncpy
wcstombs
요점
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <locale.h>
void substring_utf8(const char *source, int start, int length, char *dest) {
setlocale(LC_ALL, ""); // Set the locale
wchar_t wsource[256];
mbstowcs(wsource, source, 256); // Convert UTF-8 string to wide-character string
wchar_t wresult[256];
wcsncpy(wresult, wsource + start, length); // Extract substring in wide characters
wresult[length] = L'\0';
wcstombs(dest, wresult, 256); // Convert back to multibyte string
}
int main() {
char text[] = "こんにちは、世界!"; // UTF-8 string
char result[20];
substring_utf8(text, 5, 3, result); // Extract "世界"
printf("Substring: %s\n", result);
return 0;
}
4.5 정리
setlocale(LC_ALL, "");
mbstowcs
wcsncpy
wcstombs
5. 문자코드별 문자열 추출 방법
substring
를 직접 만들면, 유연하게 부분 문자열을 가져올 수 있다。- 동적 메모리 확보 (
malloc
) 를 이용하면, 가변 크기의 부분 문자열을 가져올 수 있다。 - 멀티바이트 문자(일본어)를 다룰 때는、
mbstowcs
/wcstombs
를 활용한다。
표준 라이브러리의 strncpy
와 strchr
로는 대응하기 어려운 경우, 자작 함수를 생성함으로써, C-gengo의 문자열 처리를 보다 강력하게 할 수 있습니다。
5.1 ASCII(1바이트 문자)의 경우
C 언어에서는、문자코드의 차이에 주의하지 않으면、문자열 추출 처리가 올바르게 동작하지 않을있을 수 있습니다。특히、日本어와 같은 멀티바이트 문자(UTF-8、Shift_JIS、EUC-JP 등)를 다룰 경우、1문자=1바이트가 아니기 때문에、단순한 strncpy
와 substring
함수로는 적절히 처리할 수 없습니다。
본 섹션에서는、문자코드별 문자열 추출 방법에 대해 자세히 설명합니다。
기본적인 부분 문자열 얻기
구현 예시
ASCII 문자는 1문자 = 1바이트 이므로、strncpy
와 substring
함수로 쉽게 처리할 수 있습니다。
5.2 UTF-8(멀티바이트 문자)의 경우
#include <stdio.h>
#include <string.h>
void substring_ascii(const char *source, int start, int length, char *dest) {
strncpy(dest, source + start, length);
dest[length] = '\0'; // Add null terminator
}
int main() {
char text[] = "Hello, World!";
char result[6];
substring_ascii(text, 7, 5, result); // Extract "World"
printf("Substring: %s\n", result);
return 0;
}
포인트
- ASCII 문자(영숫자만)의 경우는
strncpy
으로 충분히 대응 가능 '\0'
(널 문자)를 반드시 추가하세요
UTF-8의 특성
올바른 처리 방법
UTF-8에서는、1문자의 바이트 수가 1-4바이트 로 가변하기 때문에、단순히 strncpy
를 사용하면 문자 중간에 잘릴 가능성이 있습니다。
UTF-8에 대응한 부분 문자열 얻기
C 언어에서는、UTF-8을 안전하게 처리하려면 mbstowcs
를 사용하여 와이드 문자열(wchar_t
)로 변환하고、부분 문자열을 얻는 방법이 권장됩니다。
5.3 Shift_JIS(멀티바이트 문자)의 경우
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include <locale.h>
void substring_utf8(const char *source, int start, int length, char *dest) {
setlocale(LC_ALL, ""); // Set the locale
wchar_t wsource[256];
mbstowcs(wsource, source, 256); // Convert multibyte string to wide-character string
wchar_t wresult[256];
wcsncpy(wresult, wsource + start, length); // Get the substring
wresult[length] = L'\0';
wcstombs(dest, wresult, 256); // Convert wide-character string back to multibyte
}
int main() {
char text[] = "こんにちは、世界!"; // UTF-8 string
char result[20];
substring_utf8(text, 5, 3, result); // Extract "世界"
printf("Substring: %s\n", result);
return 0;
}
포인트
setlocale(LC_ALL, "");
mbstowcs
wchar_t
wcsncpy
wcstombs
Shift_JIS의 특성
Shift_JIS에 대응한 부분 문자열 얻기
Shift_JIS에서는、1문자가 1바이트 또는 2바이트가 되기 때문에、단순한 strncpy
는 문자 깨짐의 원인이 됩니다。
Shift_JIS에서의 구현
Shift_JIS의 경우에도 와이드 문자열로 변환하여 처리하는 방법이 권장됩니다。
5.4 EUC-JP(멀티바이트 문자)의 경우
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include <locale.h>
void substring_sjis(const char *source, int start, int length, char *dest) {
setlocale(LC_ALL, "Japanese"); // Set locale to handle Shift_JIS
wchar_t wsource[256];
mbstowcs(wsource, source, 256); // Convert multibyte string (Shift_JIS) to wide-character string
wchar_t wresult[256];
wcsncpy(wresult, wsource + start, length); // Extract substring
wresult[length] = L'\0';
wcstombs(dest, wresult, 256); // Convert wide-character string back to multibyte (Shift_JIS)
}
int main() {
char text[] = "こんにちは、世界!"; // Shift_JIS string (depending on environment)
char result[20];
substring_sjis(text, 5, 3, result); // Extract "世界"
printf("Substring: %s\n", result);
return 0;
}
포인트
- Shift_JIS를 올바르게 처리하려면 를 설정합니다.
- 안전하게 문자열을 처리하려면 와 를 사용하세요.
EUC-JP의 특성
EUC-JP에 대응한 부분 문자열 얻기
EUC-JP도 Shift_JIS와 마찬가지로、1문자의 바이트 수가 다르기 때문에、와이드 문자를 이용한 변환 처리가 필요합니다。
5.5 정리
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include <locale.h>
void substring_eucjp(const char *source, int start, int length, char *dest) {
setlocale(LC_ALL, "ja_JP.eucJP"); // Set locale to handle EUC-JP
wchar_t wsource[256];
mbstowcs(wsource, source, 256); // Convert multibyte string (EUC-JP) to wide-character string
wchar_t wresult[256];
wcsncpy(wresult, wsource + start, length); // Extract substring
wresult[length] = L'\0';
wcstombs(dest, wresult, 256); // Convert wide-character string back to multibyte (EUC-JP)
}
int main() {
char text[] = "こんにちは、世界!"; // EUC-JP string (depending on environment)
char result[20];
substring_eucjp(text, 5, 3, result); // Extract "世界"
printf("Substring: %s\n", result);
return 0;
}
포인트
setlocale(LC_ALL, "ja_JP.eucJP");
mbstowcs
wcstombs
6. C언어에서 문자열을 분할하는 방법
문자 코드 | 바이트 수 | 권장 처리 방법 |
---|---|---|
ASCII | 1바이트 | strncpy |
UTF-8 | 1-4바이트 | mbstowcs wcstombs |
Shift_JIS | 1 or 2바이트 | mbstowcs wcstombs |
EUC-JP | 1 or 2바이트 | mbstowcs wcstombs |
- ASCII 문자만이라면
strncpy
로 OK - UTF-8, Shift_JIS, EUC-JP의 경우는
mbstowcs
/wcstombs
를 사용 - 환경에 따라
setlocale(LC_ALL, "...");
를 적절히 설정합니다
6.1 strtok
를 사용한 문자열 분할
문자열을 분할하는 처리는, CSV 데이터 분석, 명령줄 인수 처리, 로그 데이터 분석 등 많은 경우에 필요합니다. C언어에서는, strtok
및 strtok_r
와 같은 표준 라이브러리 함수를 사용하는 방법이나, 직접 함수를 만드는 방법이 있습니다.
이 섹션에서는, 특정 구분 문자로 문자열을 분할하는 방법에 대해 자세히 설명합니다.
기본 구문
strtok
은, 지정한 구분 문자(구분자)로 문자열을 분할하는 함수입니다.
사용 예: 콤마 ,
로 문자열을 분할
char *strtok(char *str, const char *delim);
str
delim
- 반환값
- 주의점
strtok
'\0'
실행 결과
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "apple,banana,orange,grape"; // String to be split
char *token = strtok(str, ","); // Get the first token
while (token != NULL) {
printf("Token: %s\n", token);
token = strtok(NULL, ","); // Get the next token
}
return 0;
}
strtok
의 주의점
token: apple
token: banana
token: orange
token: grape
6.2 strtok_r
를 사용한 스레드 안전한 문자열 분할
- 원본 문자열을 변경합니다
strtok
구분자를'\0'
으로 바꾸어,
- 스레드 세이프하지 않음
strtok
전역 정적 변수를 내부에서 사용한다
기본 구문
strtok_r
은, strtok
의 스레드 안전 버전이며, 상태를 saveptr
에 저장하기 때문에 멀티스레드 환경에서도 안전하게 사용할 수 있습니다.입니다。
사용 예: 공백으로 문자열을 분할
char *strtok_r(char *str, const char *delim, char **saveptr);
str
delim
saveptr
strtok_r
의 장점
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "Hello World from C"; // String to be split
char *token;
char *saveptr; // Pointer to store internal state
token = strtok_r(str, " ", &saveptr); // Get the first token
while (token != NULL) {
printf("Token: %s\n", token);
token = strtok_r(NULL, " ", &saveptr); // Get the next token
}
return 0;
}
6.3 직접 함수를 사용해 문자열을 분할하기(strtok
를 사용하지 않는 방법)
- 스레드 세이프
- 여러 문자열을 동시에 처리할 수 있다
직접 함수의 사양
strtok
은 원본 문자열을 변경하기 때문에, 변경하지 않고 문자열을 분할하는 직접 함수를 만드는 것도 가능합니다。
구현 코드
- 입력
const char *source
const char delim
char tokens[][50]
- 처리
source
delim
tokens
실행 결과
#include <stdio.h>
#include <string.h>
void split_string(const char *source, char delim, char tokens[][50], int *count) {
int i = 0, j = 0, token_index = 0;
while (source[i] != '\0') {
if (source[i] == delim) {
tokens[token_index][j] = '\0';
token_index++;
j = 0;
} else {
tokens[token_index][j] = source[i];
j++;
}
i++;
}
tokens[token_index][j] = '\0';
*count = token_index + 1;
}
int main() {
char text[] = "dog,cat,bird,fish";
char tokens[10][50]; // Can store up to 10 words
int count;
split_string(text, ',', tokens, &count);
for (int i = 0; i < count; i++) {
printf("Token: %s\n", tokens[i]);
}
return 0;
}
포인트
Token: dog
Token: cat
Token: bird
Token: fish
6.4 문자열 분할의 응용(CSV 데이터 처리)
source
tokens
CSV 데이터 분석 예시
CSV(콤마 구분) 데이터를 strtok
를 사용해 분석할 수 있습니다。
실행 결과
#include <stdio.h>
#include <string.h>
int main() {
char csv[] = "Alice,24,Female\nBob,30,Male\nCharlie,28,Male"; // CSV data
char *line = strtok(csv, "\n"); // Process line by line
while (line != NULL) {
char *name = strtok(line, ",");
char *age = strtok(NULL, ",");
char *gender = strtok(NULL, ",");
printf("Name: %s, Age: %s, Gender: %s\n", name, age, gender);
line = strtok(NULL, "\n");
}
return 0;
}
6.5 요약
Name: Alice, Age: 24, Gender: Female
Name: Bob, Age: 30, Gender: Male
Name: Charlie, Age: 28, Gender: Male
결론
방법 | 장점 | 단점 |
---|---|---|
strtok | 간단히 분할할 수 있다 | 원본 문자열을 변경하다 |
strtok_r | スレッドセーフ | 사용법이 조금 복잡합니다 |
자작 함수 | 원본 문자열을 변경하지 마세요 | 코드가 길어집니다 |
CSV 분석 | 데이터 처리에 편리한 | strtok 제한에 주의하세요 |
7. 응용 예: 특정 문자 앞뒤를 추출하는 방법
- 단순한 분할이라면
strtok
- 멀티스레딩이라면
strtok_r
- 원본을 변경하고 싶지 않다면 직접 만든 함수를 사용하세요
- CSV 데이터 분석에도 적용 가능
다음 섹션에서는, 「응용 예: 특정 문자 앞뒤를 추출하는 방법」에 대해 자세히 설명합니다。
7.1 strchr
를 사용하여 특정 문자 앞의 문자열을 얻는다
문자열 처리에서는、특정 문자와 키워드의 앞뒤를 추출하는작업이 필요해지는 경우가 자주 있습니다。예를 들어、아래와 같은 경우가 생각됩니다。
- URL에서 도메인 부분만 가져오기
- 파일 경로에서 파일명을 추출
- 특정 태그나 기호 앞뒤의 문자열을 가져옵니다
C 언어에서는、strchr
와 strstr
를 이용함으로써, 이러한 처리를 구현할 수 있습니다。또한、보다 유연한 처리가 필요할 경우, 직접 함수를 만드는 방법도 유효합니다。
기본 구문
strchr
를 사용하면、특정 문자(가장 처음 발견된 것)의 위치를 지정할 수 있습니다。
사용 예: 파일 경로에서 파일 이름을 얻는다
char *strchr(const char *str, int c);
str
c
char
strchr
는 c
를 찾은 경우, 그 주소를 반환합니다。
실행 결과
#include <stdio.h>
#include <string.h>
void get_filename(const char *path, char *filename) {
char *pos = strrchr(path, '/'); // Search for the last '/'
if (pos != NULL) {
strcpy(filename, pos + 1); // Copy from the character after '/'
} else {
strcpy(filename, path); // If no '/', copy the whole path
}
}
int main() {
char path[] = "/home/user/documents/report.txt";
char filename[50];
get_filename(path, filename);
printf("Filename: %s\n", filename);
return 0;
}
포인트
Filename: report.txt
7.2 strstr
를 사용하여 특정 키워드 뒤의 문자열을 얻는다
strrchr
마지막으로 나타난 특정 문자(/
)의 위치를 가져오다pos + 1
ファイル名だけを取得可能
기본 구문
strstr
를 사용하면、특정 문자열(키워드)을 검색하고, 그 위치 이후의 문자열을 얻을 수 있습니다。
사용 예: URL에서 도메인을 얻는다
char *strstr(const char *haystack, const char *needle);
haystack
needle
strstr
는 needle
를 찾은 경우, 그 위치의 주소를 반환합니다。
실행 결과
#include <stdio.h>
#include <string.h>
void get_domain(const char *url, char *domain) {
char *pos = strstr(url, "://"); // Search for the position of "://"
if (pos != NULL) {
strcpy(domain, pos + 3); // Copy from the character after "://"
} else {
strcpy(domain, url); // If "://" is not found, copy the entire string
}
}
int main() {
char url[] = "https://www.example.com/page.html";
char domain[50];
get_domain(url, domain);
printf("Domain part: %s\n", domain);
return 0;
}
포인트
Domain part: www.example.com/page.html
7.3 strchr
를 사용하여 특정 문자 앞뒤 부분을 분할
strstr
"https://"
"http://"
"//"
pos + 3
://
사용 예: 이메일 주소에서 사용자명과 도메인을 분리
strchr
를 활용하면、특정 문자의 앞뒤 문자열을 분할하여 얻을 수 있습니다。
실행 결과
#include <stdio.h>
#include <string.h>
void split_email(const char *email, char *username, char *domain) {
char *pos = strchr(email, '@'); // Search for the position of '@'
if (pos != NULL) {
strncpy(username, email, pos - email); // Copy the part before '@'
username[pos - email] = '\0'; // Add null terminator
strcpy(domain, pos + 1); // Copy the part after '@'
}
}
int main() {
char email[] = "user@example.com";
char username[50], domain[50];
split_email(email, username, domain);
printf("Username: %s\n", username);
printf("Domain: %s\n", domain);
return 0;
}
포인트
Username: user
Domain: example.com
7.4 응용: HTML 태그 내의 특정 속성을 추출
strchr
'@'
strncpy
'@'
앞부분을 복사하고, 널 문자를 추가strcpy
'@'
뒤에 있는 부분을 복사
사용 예: <a href="URL">
에서 URL을 얻는다
HTML 태그 중에서 특정 속성을 얻는 경우에도、strstr
를 활용할 수 있습니다。
실행 결과
#include <stdio.h>
#include <string.h>
void get_href(const char *html, char *url) {
char *start = strstr(html, "href=\""); // Search for the position of href="
if (start != NULL) {
start += 6; // Move past href="
char *end = strchr(start, '"'); // Search for the next "
if (end != NULL) {
strncpy(url, start, end - start);
url[end - start] = '\0'; // Add null terminator
}
}
}
int main() {
char html[] = "<a href=\"https://example.com\">Click Here</a>";
char url[100];
get_href(html, url);
printf("Extracted URL: %s\n", url);
return 0;
}
포인트
Extracted URL: https://example.com
7.5 요약
strstr
"href=\"
strchr
"
결론
처리 내용 | 사용 함수 | 장점 |
---|---|---|
특정 문자의 앞부분을 가져오기 | strchr / strrchr | 간단하고 빠름 |
특정 문자의 뒤를 가져오기 | strstr | 키워드 검색이 가능합니다 |
특정 문자를 기준으로 앞뒤를 분리 | strchr + strncpy | 사용자 이름·도메인 분리 등에 편리 |
HTML 태그의 속성 가져오기 | strstr + strchr | 웹 스크래핑에 적용 가능 |
8. 요약
strchr
또는strstr
를 활용하면, 특정 문자·키워드의 앞뒤를 간단히 가져올 수 있다- 파일 경로 처리, URL 분석, 이메일 주소 분리 등은 많은 상황에서 유용합니다
- 웹 스크래핑과 같은 고급 처리에도 적용 가능
8.1 기사 되돌아보기
본 기사에서는, C언어에 대한 문자열 추출 방법에 대해, 기본부터 응용까지 자세히 설명했습니다. 여기서, 각 섹션의 중요한 포인트를 되돌아보고, 용도별로 최적의 방법을 정리합니다.
8.2 용도별 최적의 방법
섹션 | 내용 | 핵심 포인트 |
---|---|---|
C 언어 문자열의 기초 | C언어에서는 문자열이 배열로 처리되며, 종료 문자 가 중요합니다. | 문자열을 다룰 때는 |
표준 라이브러리에서의 추출 | strncpy strchr | strncpy 널 종료를 수동으로 추가 |
자작 함수에 의한 추출 | 유연한 함수를 만듭니다 | malloc 가변 길이 부분 문자열 추출이 가능합니다 |
문자 코드별 처리 | UTF-8, Shift_JIS, EUC-JP에 대한 대응 방법 | mbstowcs wcstombs 와이드 문자로 변환하는 것이 안전 |
문자열 분할 방법 | strtok strtok_r | strtok 원본 문자열을 변경 |
특정 문자의 앞뒤를 추출 | strchr strstr | 파일명 가져오기, URL 파싱, HTML 파싱 |
1. 부분 문자열 추출
2. 문자열 분할
사용 상황 | 최적의 방법 |
---|---|
고정 길이의 문자열을 얻고 싶습니다 | strncpy or substring() |
안전한 절단을 하고 싶다 | strncpy_s |
멀티바이트 문자(UTF-8, Shift_JIS, EUC-JP)를 다루다 | mbstowcs / wcstombs |
3. 특정 문자 전후 가져오기
사용 상황 | 최적의 방법 |
---|---|
간단히 문자열을 구분하고 싶다 | strtok |
스레드 세이프한 분할을 하고 싶다 | strtok_r |
원본 문자열을 변경하지 않고 분할하고 싶습니다. | 자작 함수(split_string() ) |
8.3 C언어 문자열 처리 주의점
사용 상황 | 최적의 방법 |
---|---|
파일 경로에서 파일 이름을 가져오기 | strrchr(path, '/') |
URL에서 도메인 부분을 가져오기 | strstr(url, "://") |
이메일 주소에서 사용자 이름과 도메인을 분리 | strchr(email, '@') |
HTML 태그에서 속성 값을 가져오기 | strstr(tag, "href=\"") + strchr(tag, '"') |
1. 널 종료 '안전한 문자열 복사 예시
'
관리 철저히
안전한 문자열 복사 예시
'2. 버퍼 오버플로우에 주의
C언어의 문자열 처리에서는, 종료 문자 '\0'
를 적절히 관리하는 것이 가장 중요합니다. 특히 strncpy
와 strchr
를 사용할 때는, 널 문자를 수동으로 추가하도록 주의하십시오.
3. 멀티바이트 문자 처리는 mbstowcs
를 사용
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "Hello, World!";
char dest[6];
strncpy(dest, src, 5);
dest[5] = '\0'; // Add null terminator for safety
printf("Substring: %s\n", dest);
return 0;
}
4. 버퍼 크기 관리
C언어의 문자열 작업에서는, 배열의 범위를 벗어나 접근하지 않도록 신중히 구현할 필요가 있습니다. 특히, strncpy
를 사용할 때는복사할 바이트 수를 제어하는 것이 중요합니다.
안전한 문자열 복사 예시
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "Hello, World!";
char dest[6];
strncpy(dest, src, sizeof(dest) - 1);
dest[5] = '\0'; // Explicitly add null terminator
printf("Substring: %s\n", dest);
return 0;
}
8.4 더 나은 학습을 위해
UTF-8 및 Shift_JIS 등 멀티바이트 문자를 다룰 경우, 단순히 strncpy
와 strlen
가 올바르게 동작하지 않는다.
따라서, 멀티바이트 문자를 다룰 때는, 한 번 mbstowcs
로 와이드 문자열로 변환하고, 적절히 처리하는 것이 권장됩니다.
#include <stdio.h>
#include <wchar.h>
#include <locale.h>
int main() {
setlocale(LC_ALL, ""); // Set the locale
char text[] = "こんにちは、世界!"; // UTF-8
wchar_t wtext[256];
mbstowcs(wtext, text, 256); // Convert to wide-character string
printf("Converted wide-character string: %ls\n", wtext);
return 0;
}
학습을 심화하기 위한 토픽
문자열 처리에서는, 필요한 메모리 크기 를 사전에 계산하고, 버퍼 오버플로우를 방지하는 것이 중요합니다. 특히, malloc
를 사용해 동적 메모리를 확보할 때는, 그 크기를 정확히 파악하도록 합시다.
8.5 요약
C언어의 문자열 처리는, 프로그램의 안전성 및 가독성을 향상시키는 중요한 스킬입니다. 본 기사에서 소개한 내용을 바탕으로, 아래 토픽을 추가로 학습하면 보다 고급 문자열 처리가 가능해집니다.
학습을 심화하기 위한 토픽
- 정규 표현식 (regex)
- 파일 조작 (fgets, fscanf을 사용한 문자열 처리)
- 메모리 관리(malloc, realloc 을 사용한 동적 문자열 처리)
- 데이터 분석 (JSON, XML 파싱 방법)
8.5 요약
- C 언어의 문자열은
char
배열로 관리되기 때문에, 종료 문자'\0'
의 처리가 중요 - 부분 문자열을 추출하려면
strncpy
,substring()
,malloc
를 사용합니다 - 문자열의 분할에는
strtok
/strtok_r
/ 자작 함수를 활용 - 특정 문자의 앞뒤를 가져오는 경우는
strchr
,strstr
를 활용 - 멀티바이트 문자(일본어)를 다룰 때는、
mbstowcs
를 이용 - 안전한 문자열 처리를 염두에 두고, 버퍼 오버플로우에 주의하세요
본 기사 내용을 활용하면, C언어에서실용적인 문자열 처리가 가능합니다. 기본적인 함수를 이해한 뒤, 자작 함수와 응용 처리에 도전하고, 보다 효율적인 코드를 작성할 수 있게 합시다!