CSVを処理するパーザーを作ってみた

職場では何かとCSVとしてデータを書き込んだり、読み込んだりすることが多い。書き込むのは簡単でも、読み込んで使うとなると文字列処理が入ってくるので難しくなる。なので、ちょっと試しに作ってみた。デリミタは引数として変えられるようにして、コンマじゃなくても融通が利くようにしてみた。

ウェブは便利だが、初歩でつまづく人も多くてどうしてもちょっと踏み込んだアルゴリズムはなかなか無いのが現実だ。このぐらいの解析作業もちょっとコピー&ペーストってなわけにもいかず、地道に自分で考えるしかないこともしょっちゅうである。不平不満を言ってもしょうがないのでためしに公開してみる。DLLにして自分用のライブラリ化するのもいいかもしれない。

strchr.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* get_token: 文字列をデリミタに従い、トークンに切り出す */
int get_token(char* crnt, int delimiter, char** output, int* num)
{
	int i        = 0;    // カウンター
	int count    = 0;    // 切り出したトークンの数
	char* next   = NULL; // 次のトークンの先頭位置
	void** token = NULL; // 文字列の先頭、または各改行の次の文字

	// 初期化
	*num   = 0;

	// (エラー処理)文字列がNULLの場合は、何もせず終了する
	if (crnt == NULL)
	{
		fprintf(stderr, "NULLポインターが渡されました\n");
		return 0;
	}

	// (エラー処理)何もせず終了する
	if (strlen(crnt) <= 0) 
	{
		fprintf(stderr, "文字列長が0です\n");
		return 0;
	}

	// トークンに分ける
	while (1)
	{
		// 文字列先頭の位置をトークンに代入する
		output[count] = crnt;

		// 次のトークンを切り出してくる
		next = strchr(crnt, delimiter);

		// デリミタが見つからないときは抜ける
		if (next == NULL) 
		{
			// デリミタは無い場合でも、
			// まだ文字列がある場合は最後の要素として格納する
			if (strlen(crnt) >= 0) 
			{
				count++;
				output[count] = crnt;
			}
			break;
		}
		else {
			*next = '\0';
		}

		// 次の文字列に行く
		crnt = next + 1;

		// トークン数をカウントアップする
		count++;
	}

	// トークン数を出力する
	*num = count;

	return 0;
}

int main(int argc, char* argv[])
{
	int i       = 0;
	int num     = 0;
	char* str   = NULL;
	char** data = NULL;

	// 入力する文字列
	str = malloc(0xFFFF);
	strcpy(str, "1,22,,333,444,555,");
	printf("INPUT: %s:(%p)\n", str, str);

	// 与えられた文字列をトークンに従い、切り分ける
	// (元々のstrは破壊される)
	data = malloc(0xFFFF);
	get_token(str, ',', data, &num);

	// 切り出してきたトークンの表示を行う
	for (i = 0; i < num; i++) 
	{
		printf("OUTPUT: %d: [%s:\t(%p)]\n", i, data[i], data[i]);
	}

	free(data);
	free(str);

	return 0;
}