엑셀 (csv) 파일 받아 정렬하기

오동환·2023년 4월 16일
0

Algorithm

목록 보기
17/23
post-thumbnail

0. 사용한 함수들

1) fgets

2) feof

3) _strdup

4) strtok

5) strcmp

1. 헤더파일

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 15790

2. 데이터를 저장할 구조체

typedef struct Data {
	char* ip;
	char* time;
	char* url;
	int status;
}Data;

Data* my_data;

3. 데이터를 읽어 구조체 배열에 저장

void read_data(char* data_name){
	my_data = (Data*)malloc(sizeof(Data) * SIZE);
	char str_tmp[1024];
	FILE* pFile = NULL;

	pFile = fopen("webLog.csv", "r");
	if (pFile != NULL)
	{
		int idx = 0;

		fgets(str_tmp, 1024, pFile);
		while (!feof(pFile) && idx < SIZE - 1) { // since idx 0 == line 2
			fgets(str_tmp, 1024, pFile);

			my_data[idx].ip = _strdup(strtok(str_tmp, ","));
			my_data[idx].time = _strdup(strtok(NULL, ","));
			my_data[idx].url = _strdup(strtok(NULL, ","));
			my_data[idx].status = atoi(strtok(NULL, ","));

			idx++;
		}
	}
	fclose(pFile);
}
  1. SIZE 크기의 구조체 배열을 생성한다.
  2. File을 열고 fgets로 첫 줄을 읽는다.
  3. while문 안에서 idx가 SIZE - 1 보다 작을 때 까지 구조체의 각 멤버에 토큰화된 데이터를 저장한다.

4. IP를 기준으로 정렬

int compare_ip(const void* m, const void* n) {
	return strcmp(((Data*)m)->ip, ((Data*)n)->ip);
}

void sort_ip() {
	qsort(my_data, SIZE - 1, sizeof(my_data[0]), compare_ip);

	for (int i = 0; i < SIZE - 1; i++) {
		printf("%s\n", my_data[i].ip);
		printf("\tTime: %s\n", my_data[i].time);
		printf("\tURL: %s\n", my_data[i].url);
		printf("\tStatus: %d\n", my_data[i].status);
	}
}
  1. 구조체 배열 정렬을 위해 qsort를 이용한다.
  2. compare_ip는 strcmp를 이용하여 m의 값이 n보다 작은 경우 음수, 같은 경우 0, 큰 경우에 양수를 리턴한다.

5. Time을 기준으로 정렬

typedef enum {
	Jan = 1,
	Feb,
	Mar,
	Apr,
	May,
	Jun,
	Jul,
	Aug,
	Sep,
	Oct,
	Nov,
	Dec
}Month;

Month string_to_enum(char* string) {
	if (strcmp(string, "Jan") == 0) {
		return Jan;
	}
	else if (strcmp(string, "Feb") == 0) {
		return Feb;
	}
	else if (strcmp(string, "Mar") == 0) {
		return Mar;
	}
	else if (strcmp(string, "Apr") == 0) {
		return Apr;
	}
	else if (strcmp(string, "May") == 0) {
		return May;
	}
	else if (strcmp(string, "Jun") == 0) {
		return Jun;
	}
	else if (strcmp(string, "Jul") == 0) {
		return Jul;
	}
	else if (strcmp(string, "Aug") == 0) {
		return Aug;
	}
	else if (strcmp(string, "Sep") == 0) {
		return Sep;
	}
	else if (strcmp(string, "Oct") == 0) {
		return Oct;
	}
	else if (strcmp(string, "Nov") == 0) {
		return Nov;
	}
	else if (strcmp(string, "Dec") == 0) {
		return Dec;
	}
	else {
		printf("Wrong month input");
		exit(-1);
	}
}

int help_compare_time(char* m, char* n) {

	char temp_m[100];
	char temp_n[100];

	strcpy(temp_m, m);
	strcpy(temp_n, n);

	char* m_day;
	char* m_month;
	int m_year;
	char* m_time;

	m_day = _strdup(strtok(temp_m, "/"));
	m_month = _strdup((strtok(NULL, "/")));
	m_year = atoi(strtok(NULL, ":"));
	m_time = _strdup(strtok(NULL, ""));

	char* n_day;
	char* n_month;
	int n_year;
	char* n_time;

	n_day = _strdup(strtok(temp_n, "/"));
	n_month = _strdup(strtok(NULL, "/"));
	n_year = atoi(strtok(NULL, ":"));
	n_time = _strdup(strtok(NULL, ""));

	int result;

	// do compare
	if (m_year ==  n_year) {
		if (string_to_enum(m_month) == string_to_enum(n_month)) {
			if (strcmp(m_day, n_day) == 0) {
				result = strcmp(m_time, n_time);
			}
			else {
				result = strcmp(m_day, n_day);
			}
		}
		else {
			if (string_to_enum(m_month) < string_to_enum(n_month)) {
				result = -1;
			}
			else if (string_to_enum(m_month) > string_to_enum(n_month)) {
				result = 1;
			}
			else {
				result = 0;
			}
		}
	}
	else {
		if (m_year < n_year) {
			result = -1;
		}
		else if (m_year > n_year) {
			result = 1;
		}
		else {
			result = 0;
		}
	}

	return result;
}


int compare_time(const void* m, const void* n) {
	return help_compare_time(((Data*)m)->time, ((Data*)n)->time);;	
}

void sort_time() {
	qsort(my_data, SIZE - 1, sizeof(my_data[0]), compare_time);

	for (int i = 0; i < SIZE - 1; i++) {
		printf("%s\n", my_data[i].time);
		printf("\tIP: %s\n", my_data[i].ip);
		printf("\tURL: %s\n", my_data[i].url);
		printf("\tStatus: %d\n", my_data[i].status);
	}
}

C는 Time을 비교하는 함수를 지원하지 않으므로 비교 함수를 직접 만들어야 했다.

  1. sort_time()은 qsort를 이용해 구조체 배열을 compare_time을 이용하여 정렬한다.
  2. compare_time은 help_compare_time을 이용하여 m이 n보다 작은 경우 -1, 같은 경우 0, 큰 경우 +1을 리턴한다.
  3. strtok함수는 데이터 버퍼를 이용하기때문에 compare_time의 m과 n에 사용하면 데이터가 손상되어 qsort가 정상적으로 작동하지 않는다.
  4. 따라서 help_compare_time에서 temp 스트링에 strcpy를 이용하여 데이터를 복사를하고 토큰화 하여 각 스트링 변수에 저장하였다.
  5. Month를 비교하기 위해 enum을 이용해 Month 자료형을 만들고, 입력된 스트링을 enum 정수값으로 바꿔주는 string_to_enum 함수를 사용하였다.
profile
게임 개발 공부하고 있어요

0개의 댓글