파싱을 하는 방법에는 여러가지가 있다.
단순한 컴마(, 또는 csv)를 이용한 방법과 본 게시물 이전에 libxml을 이용하는 방법도 있고
근래에는 JSON을 이용한 파싱을 주로 많이 이용하는 것 같다.
따라서, 다음에 이용할 수 있도록 JSON 샘플을 작성해놓고자 한다.
1. JSON 파싱 샘플 예제 (json_ex.c)
우선 아래와 같이 JSON 샘플예제 소스코드를 작성한다.
#define _CRT_SECURE_NO_WARNINGS // fopen 보안 경고로 인한 컴파일 에러 방지
#include <stdio.h> // 파일 처리 함수가 선언된 헤더 파일
#include <stdlib.h> // malloc, free 함수가 선언된 헤더 파일
#include <stdbool.h> // bool, true, false가 정의된 헤더 파일
#include <string.h> // strchr, memset, memcpy 함수가 선언된 헤더 파일
// 토큰 종류 열거형
typedef enum _TOKEN_TYPE {
TOKEN_STRING, // 문자열 토큰
TOKEN_NUMBER, // 숫자 토큰
} TOKEN_TYPE;
// 토큰 구조체
typedef struct _TOKEN {
TOKEN_TYPE type; // 토큰 종류
union { // 두 종류 중 한 종류만 저장할 것이므로 공용체로 만듦
char *string; // 문자열 포인터
double number; // 실수형 숫자
};
bool isArray; // 현재 토큰이 배열인지 표시
} TOKEN;
#define TOKEN_COUNT 20 // 토큰의 최대 개수
// JSON 구조체
typedef struct _JSON {
TOKEN tokens[TOKEN_COUNT]; // 토큰 배열
} JSON;
char *readFile(char *filename, int *readSize) // 파일을 읽어서 내용을 반환하>는 함수
{
FILE *fp = fopen(filename, "rb");
if (fp == NULL)
return NULL;
int size;
char *buffer;
// 파일 크기 구하기
fseek(fp, 0, SEEK_END);
size = ftell(fp);
fseek(fp, 0, SEEK_SET);
// 파일 크기 + NULL 공간만큼 메모리를 할당하고 0으로 초기화
buffer = malloc(size + 1);
memset(buffer, 0, size + 1);
// 파일 내용 읽기
if (fread(buffer, size, 1, fp) < 1)
{
*readSize = 0;
free(buffer);
fclose(fp);
return NULL;
}
// 파일 크기를 넘겨줌
*readSize = size;
fclose(fp); // 파일 포인터 닫기
return buffer;
}
void parseJSON(char *doc, int size, JSON *json) // JSON 파싱 함수
{
int tokenIndex = 0; // 토큰 인덱스
int pos = 0; // 문자 검색 위치를 저장하는 변수
if (doc[pos] != '{') // 문서의 시작이 {인지 검사
return;
pos++; // 다음 문자로
while (pos < size) // 문서 크기만큼 반복
{
switch (doc[pos]) // 문자의 종류에 따라 분기
{
case '"': // 문자가 "이면 문자열
{
// 문자열의 시작 위치를 구함. 맨 앞의 "를 제외하기 위해 + 1
char *begin = doc + pos + 1;
// 문자열의 끝 위치를 구함. 다음 "의 위치
char *end = strchr(begin, '"');
if (end == NULL) // "가 없으면 잘못된 문법이므로
break; // 반복을 종료
int stringLength = end - begin; // 문자열의 실제 길이는 끝 위치 - 시작 위치
// 토큰 배열에 문자열 저장
// 토큰 종류는 문자열
json->tokens[tokenIndex].type = TOKEN_STRING;
// 문자열 길이 + NULL 공간만큼 메모리 할당
json->tokens[tokenIndex].string = malloc(stringLength + 1);
// 할당한 메모리를 0으로 초기화
memset(json->tokens[tokenIndex].string, 0, stringLength + 1);
// 문서에서 문자열을 토큰에 저장
// 문자열 시작 위치에서 문자열 길이만큼만 복사
tokenIndex++; // 토큰 인덱스 증가
pos = pos + stringLength + 1; // 현재 위치 + 문자열 길이 + "(+ 1)
}
break;
}
pos++; // 다음 문자로
}
}
void freeJSON(JSON *json) // JSON 해제 함수
{
for (int i = 0; i < TOKEN_COUNT; i++) // 토큰 개수만큼 반복
{
if (json->tokens[i].type == TOKEN_STRING) // 토큰 종류가 문자열이면
free(json->tokens[i].string); // 동적 메모리 해제
}
}
int main()
{
int size; // 문서 크기
// 파일에서 JSON 문서를 읽음, 문서 크기를 구함
char *doc = readFile("example.json", &size);
if (doc == NULL)
return -1;
JSON json = { 0, }; // JSON 구조체 변수 선언 및 초기화
parseJSON(doc, size, &json); // JSON 문서 파싱
printf("Title: %s\n", json.tokens[1].string); // 토큰에 저장된 문자열 출력(Title)
printf("Genre: %s\n", json.tokens[3].string); // 토큰에 저장된 문자열 출력(Genre)
printf("Director: %s\n", json.tokens[5].string); // 토큰에 저장된 문자열 출력(Director)
freeJSON(&json); // json 안에 할당된 동적 메모리 해제
free(doc); // 문서 동적 메모리 해제
return 0;
}
2. json 샘플파일(example.json)
json 샘플파일을 작성한다. 아래는 샘플로 1개의 데이터만 작성하였다.
{
"Title": "Inception",
"Genre": "Sci-Fi",
"Director": "Christopher Nolan"
}
3. 실행
생성한 Json 데이터를 출력하려면 다음과 같이 출력된다.
/creator/json$ ./json1 example.json Title: Inception Genre: Sci-Fi Director: Christopher Nolan |
본 게시물은 아래의 경로의 블로그를 참조해서 만들었다.
반응형
최근댓글