質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

5回答

9735閲覧

文字列にカンマが含まれるCSVを構造体に読み込みたい

kanka

総合スコア26

CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

1クリップ

投稿2018/10/23 14:05

編集2018/10/25 23:40

エクセルで作成したcsvファイルを、1行ずつ構造体の配列に読み込みたいです。

C++

1struct text{ 2string a; 3string b; 4string c; 5}

csv

1A,B,X 2Apple,8,"12,32" 3Begit,"32,2",10

エクセルの書き出しでは、セルの中にカンマが入っている場合、書き出し時に"12,32"のように""で括ることで区切りのカンマと区別しています。
しかし、c++で単純な方法でカンマ区切りcsvを読み込む場合、"12,32"の中もカンマで区切られてしまいます。
そのような事態を避けるにはどのようなプログラムを作成すればよいでしょうか?
よろしくお願いします。

補足

ありがとうございます。回答を拝見させていただき自分でプログラムを作ろうとしたのですがうまくいきませんでした。
理由は、
扱うcsvファイルが、ダブルクオーテーションマークの中にさらにダブルクオーテーションマークが入っている構造をしていたためです。
単純に"で括られた部分を抜き出す処理をするだけでは正しく分離できません。
扱っているのはこんな感じのデータです。

csv

1a,"b"c,d"e",f

これを分離して以下のようにしたいです。
a
b"c,d"e
f

そのために、
string::findで、「,"」、「",」を検索したいです。
しかしfindだとstringの中の先頭しか検索できないので、二つ以上を検索できません。
どうすればよろしいでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答5

0

6年前にこんなの書きました。

StateパターンでCSVを読む

投稿2018/10/24 10:33

episteme

総合スコア16614

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

投稿2018/10/23 19:50

hichon

総合スコア5737

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

  1. "で囲まれた文字列を分離
  2. コンマを区切りにして分離

と2段階で処理するようにしましょう

投稿2018/10/23 14:19

編集2018/10/23 14:20
y_waiwai

総合スコア87719

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

解決しました。
色々教えていただいたことを試してみたのですが、何をやってもcsvをうまくカットできませんでした。
その原因は、csvの中にバックスラッシュが入っていたからでした。テキストに入っているバックスラッシュをエスケープ文字と勘違いして、そこでエラーが出ていたようです。
その際、Boost::tokenizerを用いた場合、メッセージとして以下のようなものが出ます

ErrMessage

1libc++abi.dylib: terminating with uncaught exception of type boost

(長いので途中はカット)
そして、

c++

1#ifdef BOOST_NO_EXCEPTIONS

というソース?に飛ばされます。(xcodeの場合)

解決方法
https://qiita.com/ayase/items/6897bf32e56f19fd8b3c

この方のソースコードを変更し、読み込みの際にバックスラッシュをスラッシュに変更する処理を行います。

c++

1#include <iostream> 2#include <fstream> 3#include <vector> 4#include <string> 5#include <boost/tokenizer.hpp> 6 7 8std::vector < std::vector< std::string > > parse_csv(const char* filepath) 9{ 10 std::vector< std::vector< std::string > > cells; 11 std::string line; 12 std::ifstream ifs(filepath); 13 14 15 // csvを走査 16 while (std::getline(ifs, line)) { 17 18 //ここ!!バックスラッシュが入るのを回避  19 replace(line.begin(),line.end(),'\','/'); 20 21 std::vector< std::string > data; 22 23 24 boost::tokenizer< boost::escaped_list_separator< char > > tokens(line); 25 for (const std::string& token : tokens) { 26 27 data.push_back(token); 28 } 29 30 31 cells.push_back(data); 32 } 33 34 return cells; 35} 36 37 38int main(void) 39{ 40 const auto cells = parse_csv("test.csv"); 41 for (const auto& rows : cells) { 42 for (const auto& cell : rows) { 43 std::cout << "<" << cell << "> " << std::endl; 44 } 45 std::cout << std::endl; 46 } 47 48 return 0; 49} 50

たくさんの方に回答いただき、色々試していくうちにC++への理解が深まったと思います。
今回は本当にありがとうございます。

投稿2018/10/29 12:45

kanka

総合スコア26

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

c++で単純な方法で

「単純な方法」というのが何を指すのが不明ですが,
それでだめなら「もうちょっと単純ではない方法(?)」でやればよいのでは.

例えば,単純に先頭から1文字ずつ見ていけば,カンマに出くわした際にそれが区切りなのか文字列中の文字なのかの判断はつきますよね.


扱うcsvファイルが、ダブルクオーテーションマークの中にさらにダブルクオーテーションマークが入っている構造をしていたためです。

CSVではそういう場合には,ダブルクオートは "" としてエスケープします。
そうじゃないと例えば
"a","b" という記述があったときに,これが

  • a","b という1つの要素
  • a と b という2つ要素

のどちらなのかわからないですよね.

投稿2018/10/24 01:14

編集2018/10/26 03:03
fana

総合スコア11632

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問