C++: std::vectorへのCSVデータの読み込み

概要

先日,C++でのテキストデータの一括読み込み方法を整理した。その最後に,昔はCSVファイルの読み込みに挑戦して四苦八苦したが,今ならstd::getline()を活用すれば簡単に実現できそうだと書いた。

入力データとしてCSVは手軽でよく使われる形式なので,せっかくなので改めてC++でのCSVデータの読み込み方法を整理することにした。

実装

まずは実装例を以下に掲載する。前回同様,GitHubでも公開している。

read-csv-to-vector.cpp
#include <iostream>
#include <sstream>
#include <string>
#include <vector>

int main(void) {
  std::stringstream input("11,12,13\n21,22,23\n31,32,33\n");
  std::vector<std::vector<std::string>> vv;

  for (std::string value; std::getline(input, value);) {
    vv.push_back(std::vector<std::string>());
    for (std::stringstream ss(value); std::getline(ss, value, ',');) {
      vv[vv.size()-1].push_back(value);
    }
  }

  for (auto& v : vv) {
    for (auto& e : v) std::cout << " " << e ;
    std::cout << "\n";
  }

  return 0;
}

このコードをコンパイルして実行すると,以下のようにCSVデータの要素がスペース区切りで表示される。

 11 12 13
 21 22 23
 31 32 33

説明

前回のテキストデータの読み込み同様,std::getline()を駆使して実装した。

CSVデータを2次元のstd::vectorに格納するために若干工夫した。肝となるのは以下の部分だ。

  std::stringstream input("11,12,13\n21,22,23\n31,32,33\n");
  std::vector<std::vector<std::string>> vv;

  for (std::string value; std::getline(input, value);) {
    vv.push_back(std::vector<std::string>());
    for (std::stringstream ss(value); std::getline(ss, value, ',');) {
      vv[vv.size()-1].push_back(value);
    }
  }

以下の手順で実装した。

CSVデータの読み込み手順
  1. CSVデータから1行の文字列をstd::string valueに格納
  2. std::vectorに行を追加するため,空のstd::vectorpush_back()で追加
  3. 1行文の文字列を格納したvalueから,std::getline()の入力用文字列ストリームを生成
  4. std::getline()の区切り文字に','を指定してコンマ区切りデータをvalueに格納
  5. vv[vv.size()-1].push_back(value);で最終行に要素 (列) を追加

素直にstd::getline()を使って実装した。std::vectorへの追加方法,要素サイズの拡大方法で少し頭を使った。その他,余計な一時変数が生まれないようにstd::string valueを使いまわした。

わかりやすさを重視するならば,2回目のfor文のvalueは別の名前の変数にしてもよいかもしれない。

また,前回同様にstd::getline()の第1引数のオブジェクトを以下のように変更することで,標準入力やファイルにも対応できる。

入力データごとのstd::getline()の第1引数
  • 標準入力: std::cin
  • ファイル: std::fstream ifs("file")
  • テキスト: std::stringstream ss("text")

シンプルに実装できて満足だった。

結論

C++でのCSVデータのstd::vectorへの読み込み方法を解説した。

CSVデータの読み込みはデータ処理の基本でもあるので,整理できたのはよかった。今回の実装例をベースに,必要に応じて型変換やデータの読み飛ばしなどを行えばよいだろう。

C++を始めたての頃は,変にPythonの知識があった分,Pythonと同じように実装しようとしてライブラリー関数を探し回ったりして遠回りをしていた。

安易に外部ライブラリーなどに頼るのではなく,C言語と同様に,基本的な処理を組み合わせて実装することが,シンプルでわかりやすいのかもしれない。

また何かよくある問題に遭遇したら整理したい。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です