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

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

新規登録して質問してみよう
ただいま回答率
85.49%
C++

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

Q&A

解決済

3回答

12367閲覧

データが正しく出力されません…

Removed_Past

総合スコア14

C++

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

0グッド

1クリップ

投稿2018/09/11 11:31

編集2018/09/11 12:13

前提・実現したいこと

C++を用いて自動採点のシステムを開発しているのですが、
out_of_rangeの例外がどこから発生して、どう処理したらいいのかが分かりません。
今度はデータが正しく出力されない問題が発生しました…

発生している問題・エラーメッセージ

~~terminate called after throwing an instance of 'std::out_of_range'what(): basic_string::substr: __pos (which is 4) > this->size() (which is 0)This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
~~

該当のソースコード

C++

1#include <iostream> 2#include <fstream> 3#include <string> 4#include <vector> 5#include <utility> 6#include "AnswerCheck.h" 7 8typedef vector<string> Type; 9 10Type answer; 11 12Type putdata(string s){ 13 int cnt = 0, pnt = 0, cha = 0; 14 Type buf; 15 16 while(1){ 17 if(buf.size() == 13) break; 18 if(s[cha] != ','){ 19 cnt++; 20 } 21 else{ 22 ** try{ 23 buf.push_back(s.substr(pnt + 1, cnt - 2)); 24 } 25 catch(...){ 26 buf.push_back(""); 27 } 28 pnt += ++cnt; 29 cnt = 0; 30 } 31 cha++; 32 } 33 34 return buf; 35} 36 37int main(void){ 38 ifstream ifs("data.csv"); 39 ofstream log("log.csv", ios::trunc); 40 int cnt = 0; 41 42 log << "Class,Number,A1,A2,A3,A4,A5,B1,B2,B3,B4,B5,B6,A Result,Sum Result" << endl; 43 44 string s; 45 while(getline(ifs, s)){ 46 int a_result = 0, result = 0; 47 if(cnt != 0){ 48 Type buf = putdata(s); 49 string id = buf[1]; 50 pair<string, string> user; 51 user.first = id.substr(4, 1); 52 user.second = id.substr(5, 2); 53 cout << "Class : " << user.first << endl 54 << "Number : " << user.second << endl; 55 log << user.first << "," 56 << user.second << ","; 57 for(int a = 2; a < buf.size(); a++){ 58 int score = check(buf[a], a - 2); 59 result += score; 60 if(a < 7) a_result += score; 61 log << score << ","; 62 } 63 log << a_result << "," << result << flush << endl; 64 } 65 66 cnt++; 67 } 68}

試したこと

**の場所で例外が発生しているのかと思い、try,catchを入れたのですが、変わりませんでした。

補足情報

「#include "AnswerCheck.h"」は問題採点用のヘッダで、こちらにエラーが無い事は確認済みです。
また、読み込みファイルの「data.csv」は読み込むデータが1つのみ(Googleフォームの結果を落としているので2行)の場合は問題なく動きます。

追加

「data.csv」のサンプルです。
data.csv

開発環境はMinGW6.3.0です。
エディタはTeraPadを使用しています。

回答者のご指摘からmain関数にtry,catchを入れたところ、ひとまずエラーが解消されました。
ですが、入力したデータは4つ連続しているのですが、出力した「log.csv」には以下のように無駄に空白が入ってしまいました…
良ければ原因は何処なのか教えてほしいです…
log.csv

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

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

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

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

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

tiitoi

2018/09/11 11:45

data.csv のサンプルを追記いただくことはできますか?
yohhoy

2018/09/11 12:05

デバッガ(gdbやlldb)は使えますか?開発環境も追記された方が良い気がします。
guest

回答3

0

問題点

提示された CSV ファイル

"タイムスタンプ","ユーザー名(例:sth1F45)","A1 回答欄","A2 回答欄","A3 回答欄","A4 回答欄","A5 回答欄","B1 回答欄","B2 回答欄","B3 回答欄","B4 回答欄","B5 回答欄","B6 回答欄","C1 回答欄","C2 回答欄","C3 回答欄","C4 回答欄" "2018/09/10 9:01:29 午後 GMT+9","sth1F45","ABC","AEG","ABCD","ABCE","ADHJ","ABDF","AGLK","AFJK","AEIC","AOFH","AKGJ","","","","" "2018/09/10 10:03:37 午後 GMT+9","sth1A39","ADE","ABG","ACEH","ABDHKI","AGCH","ABDFHJIJHJI","ABCIMFJMHKML","ABEGLMN","ADGIJK","DGILJLNMN","ADFKNOMPLP","a i u e o"

CSV のパーサーが不十分ではないですか。

  1. getline(ifs, s) で1行取ってくる。
  2. putdata() に渡して、カンマで分割し、リストで返す。

となっていますが、CSV の値に改行を含むものがあるので、4行目以降のパースは意図どおり動きません。
例えば、getline(ifs, s) の3回目の呼び出しで渡される引数は s="i" となっていました。

解決策

getline() を使わず、ダブルクオーテーション中に改行があることを考慮したパーサーを作成する必要があります。
自作してもよいかと思いますが、CSV を扱える C++ のライブラリを探してみてはどうでしょうか。

投稿2018/09/11 12:20

tiitoi

総合スコア21956

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

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

0

こんにちは。

basic_string::substr: __pos (which is 4) > this->size() (which is 0)

まず、basic_stringはstringのことです。basic_string<char>のtypedefがstringですので。
つまり、string.substrで posが4で長さゼロの文字列の時に例外が発生しているようなエラーメッセージです。該当し得る箇所にもう一つ以下の文がありますね。

user.first = id.substr(4, 1);

恐らくbuf[1]の長さ0の文字列が返ってくるようなデータを渡されているのだと思います。
putdata()関数に渡した s とputdata()関数の戻り値を出力して確認することがおすすめです。

投稿2018/09/11 12:10

Chironian

総合スコア23272

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

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

0

ベストアンサー

データを見ないとなんとも言えませんが、

user.first = id.substr(4, 1);
user.second = id.substr(5, 2);

この辺は問題無いですか? エラーメッセージから、怪しくあります。
また、try {} の範囲ですが、** の箇所だけでなく、他の箇所はどうでしたか?
main() の中を適当に入れてみてはどうでしょうか?

投稿2018/09/11 12:02

pepperleaf

総合スコア6383

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

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

Removed_Past

2018/09/11 12:20

ご指摘された箇所にtry catchを入れたところ、エラーは解消されました! ただ、質問を編集しましたが、今度はデータが正しく出力されないという問題が今度は発生してしまいました… よろしければこちらの方にも御力をお貸しいただけないでしょうか?
pepperleaf

2018/09/11 12:25

データ内に改行コードが入っています。 getline()は改行までを一行と見なすためです。 csvデータとして読む工夫が必要です。C++に csvデータを読み込むライブラリがあると思いますが、直ぐには分かりません。 或いは、単になる文字列として読込み、"" を一塊のデータとするコードが必要となります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問