見出し画像

C言語でCSVデータから特定の2列内の特定の範囲の行を抽出し、それらを配列に格納するまで

こんにちは。ねずみとりです。C言語でCSVファイルを読み込む機会があったためその方法とコードを共有したいと思います。また、C言語で書く意味はあまりありません。おそらくpython等を使った方が楽に書けると思います。

ファイルを開く・閉じる

ファイルの読み込みにはfopen関数を使います。引数にはファイル名の文字列とモードを入れます。読み込みの際は"r"を入れておきます。
ファイルを閉じる場合はfclose関数を使います。引数にはファイル型の変数を入れます。C言語では文字列を配列やポインタで表さなければならないのが煩わしいですね。

FILE *fp; 
char* file_name = "file.csv";

fp = fopen(file_name, "r"); 

fclose(fp)


ファイルが開けなかったときの処理

ファイル名が間違っていたときなどに備えて書いておきましょう。

if (fp == NULL)
{
	printf("%sファイルを開けません\n", file_name);
	return;
}


開いたファイルを読み込む

C言語でCSVファイルを読み込むための関数は以下の3つが挙げられます。

  • fgetc関数

  • fgets関数

  • fscanf関数

fgetc関数では文字列を1文字ずつ読み込みます。
fgets関数では文字列を1行ずつ読み込みます。
fscanf関数では書式を指定して文字列を読み込みます。

今回は特定の列を取り出したいの1行ずつは読み込みません。fgetc関数を使って1文字ずつ読み込みます。

while((c = fgetc(fp)) != EOF)
{
    //一文字ずつ
}


CSVデータから特定の2列内の特定の範囲の行を抽出し、それらを配列に格納する

引数のsearch_colmn_id_1とsearch_colmn_id_2には取り出したい列の番号を入れます。first_rowとend_rowには取り出したい行の範囲を入れます.。search_colmn_1とsearch_colmn_2には取り出した値を格納する配列を入れます。ポインタを使用すると変数の値ではなくアドレスが参照されるため引数の値を書き換えることができますため便利です。

csvはカンマでデータが区切られているため、読み込んだ文字がカンマでないときはデータ配列に入れておき、カンマになったらデータ配列をdouble型に変換して引数のsearch_colmnに格納します。

最後の列だけはカンマではなく改行で区切られているため例外として処理します。

void read_file(char* file_name,int first_row,int end_row,int search_colmn_id_1,int search_colmn_id_2,double* search_colmn_1,double* search_colmn_2)//ファイル読み込み
{
	FILE* fp;
	char* file_name = file_name;
	fp = fopen(file_name, "r");
	if (fp == NULL)
	{
		printf("%sファイルを開けません\n", file_name);
		return;
	}
	
	char c = ' ';
	int current_colmn_id = 0;
	int current_row_id = 0;
	char data[MAX_DATA_SIZE];
	int data_id = 0;
	for (int i = 0; i < MAX_DATA_SIZE; i++)data[i] = '0';
	data[MAX_DATA_SIZE - 1] = '\0';

	int search_colmn_current_id_1 = 0;
	int search_colmn_current_id_2 = 0;

	while ((c = fgetc(fp)) != EOF)
	{
		if (c == ','||c=='\n')
		{
			data_id = 0;
			double data_to_double = atof(data);

			if (first_row <= current_row_id&& current_row_id <= end_row)
			{
				if (current_colmn_id == search_colmn_id_1)//現在のIdがほしいやつなら配列に入れる
				{
					search_colmn_1[search_colmn_current_id_1] = data_to_double;
					search_colmn_current_id_1++;
				}
				if (current_colmn_id == search_colmn_id_2)
				{
					search_colmn_2[search_colmn_current_id_2] = data_to_double;
					search_colmn_current_id_2++;
				}
			}

			current_colmn_id++;
			if (c == '\n')
			{
				current_colmn_id = 0;//現在の列を0に戻す
				current_row_id++;

				if (current_row_id > end_row)
				{
					fclose(fp);
					return;
				}
			}
		}
		else
		{
			data[data_id] = c;
			data_id++;
		}
	}

	fclose(fp);
	return;
}


さいごに

ご覧いただきありがとうございます。何か間違い等がありましたらコメントで訂正をお願いします。


この記事が気に入ったらサポートをしてみませんか?