mojo's Blog
Split 본문
Split
char **ft_split(char *str, char *charset);
str, charset 을 문자열로 받았을 때 charset 에 속한 문자들을 분리해서 char ** 타입으로 값을 반환해야 한다.
str, charset 이 다음과 같다고 할 때 반환값이 무엇인지 알아보도록 한다.
str = "..,abc.,/123...456//789../, hello world ///"
charset = ".,/"
이때 반환값은 ret = { "abc", "123", "456", "789", " hello world ", 0 } 이다.
※ Split 구현 방법
① char ** 타입으로 선언한 변수 result 에 대해서 문자열에 대한 주소와 Null 주소를 넣기 위해 갯수를 미리 정해야 한다.
즉, ret = (char **)malloc(sizeof(char *) * ( ? )) <= "?" 에 대한 값을 미리 찾아줘야 한다.
"?" 에 대한 값을 반환해주는 함수를 다음과 같이 선언하였다.
int is_charset(char *str, char *charset, int idx)
{
int i;
i = 0;
while (charset[i] != '\0')
{
if (str[idx] == charset[i])
return (1);
i++;
}
return (0);
}
int get_split_size(char *str, char *charset)
{
int i;
int is_first;
int size;
i = 0;
is_first = 1;
size = 0;
while (str[i] != '\0')
{
while (is_charset(str, charset, i))
{
i++;
is_first++;
}
if (str[i] == '\0')
break ;
if (is_first)
{
size++;
is_first = 0;
}
i++;
}
return (size);
}
우선, is_first 는 단어의 첫 문자를 판별하기 위한 변수이며, is_first 값이 0 이 아닐 경우 단어의 갯수 size 를 증가시킨다.
첫 문자부터 하나하나 접근할 때 charset 에 속한 문자일 경우 패스하고 charset 에 속하지 않은 문자일 경우 멈춰서 해당 문자가 '\0' 문자가 아닐 경우 is_first 값에 따라 단어의 갯수를 카운팅하면서 접근해가는 방식이다.
아래와 같은 그림으로 charset 에 속하지 않은 문자이면서 is_first 가 0이 아닌 경우 단어의 갯수를 카운팅 해주면 된다.
② ① 에서 얻은 단어의 갯수를 통해 char ** 타입의 동적할당을 다음과 같이 할 수 있다.
split_size = get_split_size(str, charset);
ret = (char **)malloc(sizeof(char *) * (split_size + 1));
split_size + 1 을 해준 이유는 ret[split_size] = 0 즉, 마지막에 Null 값을 할당하여 문자열이 끝났음을 암시하기 위해서이다.
그리고 다시 ① 방법과 동일하게 첫 문자부터 하나씩 접근해가면서 다음과 같은 작업을 수행한다.
- 해당 문자가 charset 일 경우 : 단순하게 다음 문자로 넘어간다.
- 해당 문자가 charset 이 아닐 경우 : '\0' 문자일 경우 while 루프를 빠져나오고 그게 아닐 경우 charset 을 만날때까지 문자열의 길이를 구한 후, (char *) 타입의 동적할당을 한다.
위와 같은 작업은 다음과 같은 코드로 수행할 수 있다.
i = 0;
j = 0;
while (str[i] != '\0')
{
while (is_charset(str, charset, i))
i++;
if (str[i] == '\0')
break ;
len = get_length(str, charset, i);
ret[j] = (char *)malloc(sizeof(char) * (len + 1));
go_malloc(ret[j++], str, len, i);
i += len;
}
ret[j] = 0;
이때 i 변수를 각 문자를 접근하기 위한 용도, j 변수를 ret[j] 에 (char *) 타입으로 malloc 을 하여 문자열을 채우기 위한 용도이다.
우선 get_length() 는 현재 charset 이 아닌 첫 문자의 인덱스로부터 시작하여 charset 인 문자의 인덱스의 gap 을 통해 charset 사이의 단어의 길이를 구할 수 있다.
get_length() 함수는 다음과 같다.
int get_length(char *str, char *charset, int idx)
{
int i;
i = 0;
while (str[i + idx] != '\0')
{
if (is_charset(str, charset, i + idx))
break ;
i++;
}
return (i);
}
그리고 go_malloc(ret[j++], str, len, i) 함수를 통해서 charset 사이에 존재하는 단어를 채워야 한다.
go_malloc() 함수를 통해서 단어를 채우고 while 루프가 끝나서 ret[j] = 0 을 한다면 다음 그림과 같이 ret 이 형성된다.
③ go_malloc() 함수는 (char *) 타입으로 (단어의 길이 + 1) 만큼 할당한 영역인 ret[j] 에 단어를 채워주는 함수이다.
우선 go_malloc 함수의 코드를 보도록 한다.
void go_malloc(char *ret, char *str, int len, int idx)
{
int i;
i = 0;
while (i < len)
{
ret[i] = str[idx + i];
i++;
}
ret[i] = '\0';
}
idx는 charset 이 아닌 첫 문자의 시작인 인덱스이다.
즉, idx와 단어의 길이인 len 을 통해 단어를 채워줄 수 있으며 마지막에 널문자 ('\0') 를 넣어줘야 한다.
split 함수를 구현한 전체 코드는 다음과 같다.
#include <stdlib.h>
int is_charset(char *str, char *charset, int idx)
{
int i;
i = 0;
while (charset[i] != '\0')
{
if (str[idx] == charset[i])
return (1);
i++;
}
return (0);
}
int get_split_size(char *str, char *charset)
{
int i;
int is_first;
int size;
i = 0;
is_first = 1;
size = 0;
while (str[i] != '\0')
{
while (is_charset(str, charset, i))
{
i++;
is_first++;
}
if (str[i] == '\0')
break ;
if (is_first)
{
size++;
is_first = 0;
}
i++;
}
return (size);
}
int get_length(char *str, char *charset, int idx)
{
int i;
i = 0;
while (str[i + idx] != '\0')
{
if (is_charset(str, charset, i + idx))
break ;
i++;
}
return (i);
}
void go_malloc(char *ret, char *str, int len, int idx)
{
int i;
i = 0;
while (i < len)
{
ret[i] = str[idx + i];
i++;
}
ret[i] = '\0';
}
char **ft_split(char *str, char *charset)
{
char **ret;
int split_size;
int i;
int j;
int len;
split_size = get_split_size(str, charset);
ret = (char **)malloc(sizeof(char *) * (split_size + 1));
i = 0;
j = 0;
while (str[i] != '\0')
{
while (is_charset(str, charset, i))
i++;
if (str[i] == '\0')
break ;
len = get_length(str, charset, i);
ret[j] = (char *)malloc(sizeof(char) * (len + 1));
go_malloc(ret[j++], str, len, i);
i += len;
}
ret[j] = 0;
return (ret);
}