C++でそのまま使えるCSV読み取りクラス

**2019年12月11日追記**
改良版書きましたので、[こちら](https://qiita.com/takoyaki3/items/92d45ab1cab0bf956396)をおススメします。

**2019年12月10日追記**
この記事は、CSVファイルを一括で読み取るプログラムです。2年前はよくこのコードを使っていたのですが、最近大学などで大きなCSVを読み取る機会が増えてきたこともあり、1行ずつ読み取るために、このコードは使っていません（個人的に）。この記事もたまにストックされたりするので、新しく、[C++でCSVファイルを1行ずつ読み取る処理の記事を書きました](https://qiita.com/takoyaki3/items/34677decc70f2f14ef62)ので、併せてご覧ください。

C++の標準ライブラリで、ソースコードにコピーしてそのまま使えるCSVファイルを簡単に読み取れるクラスです。簡単なものですが、案外よく使う処理なので。

#機能
bool Load(string ファイル名) ;
ファイル名からCSVファイルを読み込みます。

wstring w(int y,int x);
CSVファイルの行（y）と列（x）を指定してセルをwstring型で取得します。

int i(int y,int x);
CSVファイルの行（y）と列（x）を指定してセルをint型で取得します。

int size_y();
CSVファイルの行数を取得します。

int size_x(int y);
行を指定して、CSVファイルの列数を取得します。

void SetComma(wchar_t c);
区切り文字を指定します。この関数を使用しないとき、標準で","が区切りに使用されます。

コンストラクタとして、ファイルを読み込むこともできます。

#ソースコード（ワイド文字：wchar_t、wstring）

```C++:MyCsv.cpp

#include <iostream>
#include <fstream>
#include <deque>
#include <string>

using namespace std;

const int MaxLen = 1024;

class MyCSV {
private:
	deque<deque<wstring>> csvfile;
	wchar_t comma;	//区切りとなるカンマ。
public:
	bool Load(string fname);
	wstring w(int y, int x);
	int i(int y, int x);
	int size_y();
	int size_x(int y);
	void SetComma(wchar_t c) { comma = c; }
	MyCSV() { comma = L','; }
	MyCSV(string fname) { comma = L','; Load(fname); }
};

bool MyCSV::Load(string fname) {
	
	//ワイド文字変換用のロケール設定
	std::locale::global(std::locale("japanese"));

	//ファイル
	wifstream ifs;
	ifs.open(fname.c_str());
	while (!ifs.eof()) {
		wchar_t c = 0;
		wstring line;
		getline(ifs, line);
		line.push_back(comma);
		line.push_back('\0');

		deque<wstring> cell;

		for (int i = 0, k = 0; i < line.size(); i++) {
			if (line[i] == comma) {
				wstring s = line.substr(k, i - k);
				i++;
				k = i;
				cell.push_back(s);
			}
		}

		csvfile.push_back(cell);
	}

	ifs.close();

	return 1;
}

wstring MyCSV::w(int y, int x) {
	if (x < 0 || y < 0) return L"";
	if (y >= csvfile.size()) return L"";
	if (x >= csvfile[y].size()) return L"";

	return csvfile[y][x];
}

int MyCSV::i(int y,int x) {
	wstring s = w(y, x);
	if (s.size() == 0) return -1;
	int n = _wtoi(s.c_str());
	return n;
}

int MyCSV::size_y() {
	return csvfile.size();
}

int MyCSV::size_x(int y) {
	if (y < 0 || y >= csvfile.size()) return -1;
	return csvfile[y].size();
}

```

#ソースコード（マルチ文字：char、string）

```C++:MyCsv.cpp

#include <iostream>
#include <fstream>
#include <deque>
#include <string>

using namespace std;

const int MaxLen = 1024;

class MyCSV_a {
private:
	deque<deque<string>> csvfile;
	char comma;	//区切りとなるカンマ。
public:
	bool Load(string fname);
	string w(int y, int x);
	int i(int y, int x);
	int size_y();
	int size_x(int y);
	void SetComma(char c) { comma = c; }
	MyCSV() { comma = L','; }
	MyCSV(string fname) { comma = ','; Load(fname); }
};

bool MyCSV_a::Load(string fname) {
	
	//ワイド文字変換用のロケール設定
	std::locale::global(std::locale("japanese"));

	//ファイル
	ifstream ifs;
	ifs.open(fname.c_str());
	while (!ifs.eof()) {
		char_t c = 0;
		string line;
		getline(ifs, line);
		line.push_back(comma);
		line.push_back('\0');

		deque<string> cell;

		for (int i = 0, k = 0; i < line.size(); i++) {
			if (line[i] == comma) {
				string s = line.substr(k, i - k);
				i++;
				k = i;
				cell.push_back(s);
			}
		}

		csvfile.push_back(cell);
	}

	ifs.close();

	return 1;
}

string MyCSV_a::w(int y, int x) {
	if (x < 0 || y < 0) return L"";
	if (y >= csvfile.size()) return L"";
	if (x >= csvfile[y].size()) return L"";

	return csvfile[y][x];
}

int MyCSV_a::i(int y,int x) {
	string s = w(y, x);
	if (s.size() == 0) return -1;
	int n = _wtoi(s.c_str());
	return n;
}

int MyCSV_a::size_y() {
	return csvfile.size();
}

int MyCSV_a::size_x(int y) {
	if (y < 0 || y >= csvfile.size()) return -1;
	return csvfile[y].size();
}

```

#注意事項
・日頃、ワイド文字版を使用していて、今回マルチバイト版を作成してみたので、マルチバイト版はきちんと動作するか不明な部分もあります。
・行数は、ファイルによっては最後に空白の行がカウントされてしまうことがあるので、forループで行にアクセスする際などにのみご使用ください。
・エラー処理をあまりしていません。ご注意ください。
・このクラスを使用する場合は、必ずコードを吟味して、悪影響がないことを確認してからご使用ください。本コードを使用した際の不利益には一切の責任を負いません。なお、問題が生じた際はコメントにてご報告くださると幸いです。

#想定される使い方
プログラムの独自データなど、CSV形式で保存すると読み書きが簡単にできて便利です。タグの代わりに下のようにしています。（本当はXMLとかを使った方がいいのでしょうが、CSVの方がどの言語でも比較的簡単に１から読み取るプログラムを書けるのでいつもこちらを使っています。）

| #Class A    |        |              |
|:------------|-------:|:------------:|
| x           |      1 |              |
| y           |     22 |              |
| z           |    333 |              |
| Text        |  Hello |              |

| #Class B    |        |              |
|:------------|-------:|:------------:|
| a           |      4 |              |
| b           |     55 |              |
| c           |    666 |              |