mojo's Blog

Split 본문

42 seoul

Split

_mojo_ 2022. 2. 22. 13:43

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);
}

'42 seoul' 카테고리의 다른 글

hexdump  (2) 2022.02.25
tail  (0) 2022.02.22
Comments