「C言語/サンプル/CSVファイルの読込ソート出力2」の編集履歴(バックアップ)一覧はこちら
追加された行は緑色になります。
削除された行は赤色になります。
CSVファイルを読み込みソートして出力するサンプル(qsort, strtok使用版)です。
* 目次
#contents(fromhere=true)
* ポイント
+ CSVファイルを読み込んで、一行ずつ構造体にセットします。
++ strtok関数で","または"\nの位置を探して項目の文字を取り出します。
++ strtok関数は、元の文字列に\0を差し込む事で、簡単に文字列を取り出せるようにしているみたいです。
+ 構造体の配列をソートします。
++ 項目ごとに分割しているので、好きな項目でソートできます。
++ qsortで使うRecord構造体比較関数compRecordを作ります。
++ qsortのパラメータは1.ソートするデータの配列 2.ソートするデータの個数 3.データ一個あたりのサイズ 4.比較関数のポインタです。
+ 構造体をCSV形式で出力します。
++ fprintf(fp, "%d","%s","%s", ...)でごりごりっと出力します。
前回[[C言語/サンプル/CSVファイルの読込ソート出力]]を作った後で、qsort関数とstrtok関数の存在を知ったので
今回はqsort strtok関数を使って修正しました。
きっと、自力でバブルソートするより早いし、ソースコードもちょっとすっきりしました。
* サンプルソース
#highlight(c){{
// C言語/サンプル/CSVファイル読込sort出力
// CSVファイルを読み込んで、構造体に設定しソートしてから再度CSVファイルに出力するサンプルです。
// qsort strtok使用版
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Record構造体
struct Record {
// インデックス
int idx;
// タイトル
char title[100];
// 日付
char date[11];
};
// CSVファイルから読み込んだ文字列をRecord構造体に設定します
void setRecord(struct Record* pR, char* str) {
int i = 0;
// 最初の","を探す
char* pStr = strtok(&str[1], "\",\"");
while (pStr) {
switch (i) {
case 0:
// インデックス
pR->idx = atoi(pStr);
break;
case 1:
// タイトル
strcpy(pR->title, pStr);
break;
case 2:
// 日付
strcpy(pR->date, pStr);
break;
default:
break;
}
i++;
// ","を探す
pStr = strtok(NULL, "\",\"");
if (pStr == NULL ) {
// ","がない場合、最後の"を探す
pStr = strtok(NULL, "\"\n");
}
}
}
// ポイント2.3 Record構造体比較関数を作ります。
// Record構造体比較関数
// qsortから呼び出され、比較結果を返す事でソートを実現します。
int compRecord(const void * p1, const void * p2) {
struct Record *r1 = *((struct Record **)p1);
struct Record *r2 = *((struct Record **)p2);
// 文字列比較
// ポイント2.2 構造体に入れたので好きな項目でソートできます
int cmp = strcmp(r1->date, r2->date);
if (cmp != 0) {
// 日付が違う場合、strcmpの結果をそのまま返します
return cmp;
}
// 日付が同じ場合、インデックスを比較します
if(r1->idx > r2->idx) {
return 1;
} else if (r1->idx < r2->idx) {
return -1;
}
// インデックスも同じ場合0を返します
return 0;
}
// CSVファイル出力
void output(FILE* fp, struct Record** out, int size) {
int i;
printf("sort後\n");
for (i = 0; i < size; i++) {
// ポイント3 カンマ区切りの文字列を作成して出力します
fprintf(fp, "\"%d\",\"%s\",\"%s\"\n", out[i]->idx, out[i]->title,
out[i]->date);
printf("\"%d\",\"%s\",\"%s\"\n", out[i]->idx, out[i]->title,
out[i]->date);
}
}
int main(int argc, char *argv[]) {
char str[255];
// 構造体の配列
struct Record record[100];
// 構造体のポインタの配列(ソート用)
struct Record *sorted[100];
int i = 0, size;
// fopen(ファイル名, オプション)でファイルを開きます
FILE* fpr = fopen(argv[1], "r");
FILE* fpw = fopen(argv[2], "w");
// ファイルを開けない場合、FILEのポインタがNULLになります
if (fpr == NULL || fpw == NULL) {
puts("ファイルが開けないよ!");
return EXIT_FAILURE;
}
printf("sort前\n");
// fgets(読み込むバッファ, バッファのサイズ, FILEのポインタ)で一行ずつ読み込みます
while (fgets(str, 255, fpr)) {
// 読み込んだ内容をそのまま出力
printf(str);
// ポイント1 読み込んだテキストを、分解して構造体の配列に設定します。
// Record構造体にデータを設定
setRecord(&record[i], str);
i++;
}
// サイズを保存
size = i;
// 出力用ポインタ配列にRecordのポインタをすべて設定する
for (i = 0; i < size; i++) {
sorted[i] = &record[i];
}
// ポイント2 構造体の配列をソートします
// qsortのパラメータは1.ソートするデータの配列 2.ソートするデータの個数 3.データ一個あたりのサイズ 4.比較関数のポインタ
qsort(sorted, size, sizeof(sorted[0]), compRecord);
// 出力ファイルに書き込みます
output(fpw, sorted, size);
// ファイルをクローズ
fclose(fpr);
fclose(fpw);
return EXIT_SUCCESS;
}
}}
* 読み込ませたCSVファイル &ref(sort.csv)
"1","CSV読込ソート出力の","2011/01/01"
"2","テスト中","2012/10/01"
"3","読み込めてますかー","2010/09/10"
"4","もっと行を","2011/01/01"
"5","増やしてみましょう","2012/10/01"
"6","これぐらいかな?","2010/09/10"
* 実行結果
&ref(CSVファイルの読込ソート出力2.png)
* サンプルダウンロード
サンプルソース &ref(sortCsv2.c)
読み込ませたCSV &ref(sort.csv)
* コメント(バグ、間違い、こんな情報が欲しい等ありましたら)
#pcomment(reply)
* アンケート(このページの情報はお役に立ちましたか?)
#tvote("役に立った[4]","役に立たない[0]","分かりにくい[2]","間違っている[0]","...[1]",""の条件が足りない[1]","うざい[15]","楽しい[1]")
CSVファイルを読み込みソートして出力するサンプル(qsort, strtok使用版)です。
* 目次
#contents(fromhere=true)
* ポイント
+ CSVファイルを読み込んで、一行ずつ構造体にセットします。
++ strtok関数で","または"\nの位置を探して項目の文字を取り出します。
++ strtok関数は、元の文字列に\0を差し込む事で、簡単に文字列を取り出せるようにしているみたいです。
+ 構造体の配列をソートします。
++ 項目ごとに分割しているので、好きな項目でソートできます。
++ qsortで使うRecord構造体比較関数compRecordを作ります。
++ qsortのパラメータは1.ソートするデータの配列 2.ソートするデータの個数 3.データ一個あたりのサイズ 4.比較関数のポインタです。
+ 構造体をCSV形式で出力します。
++ fprintf(fp, "%d","%s","%s", ...)でごりごりっと出力します。
前回[[C言語/サンプル/CSVファイルの読込ソート出力]]を作った後で、qsort関数とstrtok関数の存在を知ったので
今回はqsort strtok関数を使って修正しました。
きっと、自力でバブルソートするより早いし、ソースコードもちょっとすっきりしました。
* サンプルソース
#highlight(c){{
// C言語/サンプル/CSVファイル読込sort出力
// CSVファイルを読み込んで、構造体に設定しソートしてから再度CSVファイルに出力するサンプルです。
// qsort strtok使用版
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Record構造体
struct Record {
// インデックス
int idx;
// タイトル
char title[100];
// 日付
char date[11];
};
// CSVファイルから読み込んだ文字列をRecord構造体に設定します
void setRecord(struct Record* pR, char* str) {
int i = 0;
// 最初の","を探す
char* pStr = strtok(&str[1], "\",\"");
while (pStr) {
switch (i) {
case 0:
// インデックス
pR->idx = atoi(pStr);
break;
case 1:
// タイトル
strcpy(pR->title, pStr);
break;
case 2:
// 日付
strcpy(pR->date, pStr);
break;
default:
break;
}
i++;
// ","を探す
pStr = strtok(NULL, "\",\"");
if (pStr == NULL ) {
// ","がない場合、最後の"を探す
pStr = strtok(NULL, "\"\n");
}
}
}
// ポイント2.3 Record構造体比較関数を作ります。
// Record構造体比較関数
// qsortから呼び出され、比較結果を返す事でソートを実現します。
int compRecord(const void * p1, const void * p2) {
struct Record *r1 = *((struct Record **)p1);
struct Record *r2 = *((struct Record **)p2);
// 文字列比較
// ポイント2.2 構造体に入れたので好きな項目でソートできます
int cmp = strcmp(r1->date, r2->date);
if (cmp != 0) {
// 日付が違う場合、strcmpの結果をそのまま返します
return cmp;
}
// 日付が同じ場合、インデックスを比較します
if(r1->idx > r2->idx) {
return 1;
} else if (r1->idx < r2->idx) {
return -1;
}
// インデックスも同じ場合0を返します
return 0;
}
// CSVファイル出力
void output(FILE* fp, struct Record** out, int size) {
int i;
printf("sort後\n");
for (i = 0; i < size; i++) {
// ポイント3 カンマ区切りの文字列を作成して出力します
fprintf(fp, "\"%d\",\"%s\",\"%s\"\n", out[i]->idx, out[i]->title,
out[i]->date);
printf("\"%d\",\"%s\",\"%s\"\n", out[i]->idx, out[i]->title,
out[i]->date);
}
}
int main(int argc, char *argv[]) {
char str[255];
// 構造体の配列
struct Record record[100];
// 構造体のポインタの配列(ソート用)
struct Record *sorted[100];
int i = 0, size;
// fopen(ファイル名, オプション)でファイルを開きます
FILE* fpr = fopen(argv[1], "r");
FILE* fpw = fopen(argv[2], "w");
// ファイルを開けない場合、FILEのポインタがNULLになります
if (fpr == NULL || fpw == NULL) {
puts("ファイルが開けないよ!");
return EXIT_FAILURE;
}
printf("sort前\n");
// fgets(読み込むバッファ, バッファのサイズ, FILEのポインタ)で一行ずつ読み込みます
while (fgets(str, 255, fpr)) {
// 読み込んだ内容をそのまま出力
printf(str);
// ポイント1 読み込んだテキストを、分解して構造体の配列に設定します。
// Record構造体にデータを設定
setRecord(&record[i], str);
i++;
}
// サイズを保存
size = i;
// 出力用ポインタ配列にRecordのポインタをすべて設定する
for (i = 0; i < size; i++) {
sorted[i] = &record[i];
}
// ポイント2 構造体の配列をソートします
// qsortのパラメータは1.ソートするデータの配列 2.ソートするデータの個数 3.データ一個あたりのサイズ 4.比較関数のポインタ
qsort(sorted, size, sizeof(sorted[0]), compRecord);
// 出力ファイルに書き込みます
output(fpw, sorted, size);
// ファイルをクローズ
fclose(fpr);
fclose(fpw);
return EXIT_SUCCESS;
}
}}
* 読み込ませたCSVファイル &ref(sort.csv)
"1","CSV読込ソート出力の","2011/01/01"
"2","テスト中","2012/10/01"
"3","読み込めてますかー","2010/09/10"
"4","もっと行を","2011/01/01"
"5","増やしてみましょう","2012/10/01"
"6","これぐらいかな?","2010/09/10"
* 実行結果
&ref(CSVファイルの読込ソート出力2.png)
* サンプルダウンロード
サンプルソース &ref(sortCsv2.c)
読み込ませたCSV &ref(sort.csv)
* コメント(バグ、間違い、こんな情報が欲しい等ありましたら)
#pcomment(reply)
* アンケート(このページの情報はお役に立ちましたか?)
#tvote("役に立った[8]","役に立たない[0]","分かりにくい[4]","間違っている[0]","...[1]",""の条件が足りない[1]","うざい[20]","楽しい[1]","にょ[2]")