久しぶりにCで書いたのでメモ。ポイントは以下。
CSV | strstr()&strcpy()とstrtok()による2パターンで記載 |
---|---|
ハッシュ | ENTRY , hsearch_data , hsearch_r() を使用 |
構造体 | 内部に文字列の配列(2次元配列?)を保持 |
#include <stdio.h> #include <stdlib.h> #include <string.h> #define __USE_GNU #include <search.h> #define SOKUTEI_FILENAME "SOKUTEI_DAT.csv" /* 測定データ */ #define SOKUTEI_CSV_LEN 512 /* 測定データの1行文字数 */ #define MEMBER_IDS_FILENAME "MB_ID2MB_SID.CSV" /* 会員ID->会員SID */ #define MEMBER_IDS_SIZE 20000 /* 最大会員数. TODO:将来の会員増加を考慮 */ #define MID2MSID_CSV_LEN 20 /* 会員ID->会員SIDの1行文字数 */ ENTRY entry_members; /* 会員ID->会員SIDを保持するhash map */ ENTRY* entry_members_result; struct hsearch_data tab; typedef struct { char member_id[11]; /* 会員ID. いずれも \0を格納する為、長さ+1 byte */ char use_date[9]; /* 測定日 */ char branch_id[3]; /* 分岐種別 */ char branch_no[3]; /* 分岐NO */ char val_h[24][17]; /* 量(時間別) */ char val_tz[4][17]; /* 量(時間帯別) */ char val_day[17]; /* 量(終日) */ } SOKUTEI_DATA_COLS; int parse_sokutei_csv(char *sk_line, SOKUTEI_DATA_COLS *sk_cols); int main(void) { /* 会員ID->会員SID の変換HASHをload */ load_member_id2sid(); FILE *sk_fp; char sk_fname[] = SOKUTEI_FILENAME; if ((sk_fp = fopen(sk_fname, "r")) == NULL) { fprintf(stderr, "can't open file %s\n", sk_fname); exit(1); } char sk_line[SOKUTEI_CSV_LEN] = {'\0'}; int i = 0; char member_id_pre[10] = {"\0"}; char member_sid[10]; while ( fgets(sk_line, SOKUTEI_CSV_LEN, sk_fp) != NULL ) { if (i++ == 0 || /* 1行目はヘッダ行の為、読み飛ばし */ strlen(sk_line) == 0 ){ continue; } sk_line[strlen(sk_line) - 1] = '\0'; /* 行末の改行コード削除 */ /* 測定データCSVをパース */ SOKUTEI_DATA_COLS sk_cols; parse_sokutei_csv(sk_line, &sk_cols); /* 会員ID->会員SID 変換 */ if(strcmp(sk_cols.member_id, member_id_pre) != 0) { entry_members.key = (char*)malloc(10); sprintf(entry_members.key, "%s", sk_cols.member_id); int ret = hsearch_r(entry_members, FIND, &entry_members_result, &tab); if(ret == 0 ){ sprintf(member_sid,"%s","\0"); } else { sprintf(member_sid,"%s",entry_members_result->data); } } /* 測定データのメモリ使用量を出力する場合、以下のコメントを解除 */ /* perlなら、Devel::Size を使用 */ /* fprintf(stderr,"SOKUTEI DATA SIZE=%d bytes\n", sizeof(sk_cols) ); */ int h = 0; while(h <= 23 ){ fprintf(stdout, "%s,%s,%s,%s,%s,%d,%s\n", sk_cols.member_id, member_sid, sk_cols.use_date, sk_cols.branch_id, sk_cols.branch_no, h, /* hour */ sk_cols.val_h[h] ); h++; } } fclose(sk_fp); return 0; } /* 測定データCSVのparse */ int parse_sokutei_csv(char *sk_line, SOKUTEI_DATA_COLS *sk_cols){ char *p_sep, *p_end; /* セパレータ(,)と最終文字の位置(pointer) */ p_end = sk_line + strlen(sk_line); p_sep = strstr(sk_line,","); *(p_sep++) = 0; /* セパレータをnullにすることで、切り出し */ strcpy(sk_cols->member_id, sk_line); sk_line = p_sep; p_sep = strstr(sk_line,","); *(p_sep++) = 0; strcpy(sk_cols->use_date, sk_line); sk_line = p_sep; p_sep = strstr(sk_line,","); *(p_sep++) = 0; strcpy(sk_cols->branch_id, sk_line); sk_line = p_sep; p_sep = strstr(sk_line,","); *(p_sep++) = 0; strcpy(sk_cols->branch_no, sk_line); sk_line = p_sep; /* 時間別の値 */ int i = 0; while(i <= 23 ){ p_sep = strstr(sk_line,","); *(p_sep++) = 0; strcpy(sk_cols->val_h[i], sk_line); sk_line = p_sep; i++; } /* 時間帯別の値 */ i = 0; while(i <= 3 ){ p_sep = strstr(sk_line,","); *(p_sep++) = 0; strcpy(sk_cols->val_tz[i], sk_line); sk_line = p_sep; i++; } /* その日の合計値 */ p_sep = strstr(sk_line,","); *(p_sep++) = 0; strcpy(sk_cols->val_day, sk_line); return 0; } /* int parse_sokutei_csv_3_tmp(char *sk_line, SOKUTEI_DATA_COLS *sk_cols){ */ /* char *p_sep, *p_end; /\* セパレータ(,)と最終文字の位置(pointer) *\/ */ /* p_end = sk_line + strlen(sk_line); */ /* while(1){ */ /* if( !(p_sep = strstr(sk_line,",") ) ){ */ /* if (pStr >= pEnd) break; */ /* p_sep = p_end; */ /* } else { */ /* *(ptr++) = 0; /* } */ /* printf("@:%s\n",pStr); */ /* /\* 次の検索位置 *\/ */ /* pStr = ptr; */ /* } */ /* } */ /* 会員ID->会員SID のHASH MAP作成 */ /* なんとなくcsv parseには、strtok()を使用 */ int load_member_id2sid() { /* おまじないらしい */ memset(&tab, 0, sizeof(tab)); hcreate_r(MEMBER_IDS_SIZE, &tab); /* create hash */ char *member_ids_filename = MEMBER_IDS_FILENAME; FILE *mb_fp; if( (mb_fp = fopen(member_ids_filename, "r")) == NULL){ fprintf(stderr, "can't open file %s\n", member_ids_filename); exit(1); } char readline[MID2MSID_CSV_LEN] = {'\0'}; while ( fgets(readline, MID2MSID_CSV_LEN, mb_fp) != NULL ) { readline[strlen(readline) - 1] = '\0'; /* 行末の改行コード削除 */ entry_members.key = (char*)malloc(10); entry_members.data = (char*)malloc(10); /* split csv by strtok() */ sprintf(entry_members.key, "%s", strtok(readline, ",")); /* member_id */ sprintf(entry_members.data,"%s", strtok(NULL, ",")); /* member_sid */ int ret = hsearch_r(entry_members, ENTER, &entry_members_result, &tab); if(ret == 0 ){ fprintf(stderr, "fail add hash entry\n"); return 1; } } fclose(mb_fp); return 0; }