🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
CSV

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

C++

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

MinGW

MinGW(ミン・ジー・ダブリュー)は GNUツールチェーンのWindows移植版です。 ランタイムライブラリと開発ツールで構成されています。

Sublime Text

SublimeTextとは、オーストラリアのSublime HQ Pty Ltdが提供しているテキストエディターのことです。Mac/Windows/Linuxでの利用が可能で、柔軟にカスタマイズできたり、多くの言語に対応していくこともあり、海外や日本国内でも人気のあるエディターです。

Q&A

解決済

2回答

11274閲覧

【C++】.csvファイルを配列に読み込み、行、列を取得したい

退会済みユーザー

退会済みユーザー

総合スコア0

CSV

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

C++

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

MinGW

MinGW(ミン・ジー・ダブリュー)は GNUツールチェーンのWindows移植版です。 ランタイムライブラリと開発ツールで構成されています。

Sublime Text

SublimeTextとは、オーストラリアのSublime HQ Pty Ltdが提供しているテキストエディターのことです。Mac/Windows/Linuxでの利用が可能で、柔軟にカスタマイズできたり、多くの言語に対応していくこともあり、海外や日本国内でも人気のあるエディターです。

0グッド

0クリップ

投稿2018/08/16 11:57

編集2018/08/17 13:17

前提・実現したいこと

私は現在、csv化したファイルを二次元配列に読み込み、指定した値と一致するデータの行数、列数(Excelで開いた時のような)を取得するプログラムを組みたいと考えています。そこでこちらの質問(https://teratail.com/questions/94162)を参考に、「csvファイルを読み込み、二次元配列に格納、それを配列から.csvに出力して格納を確認する」として以下のプログラムを書いたのですが、現在2つの問題が発生しています。

①下のファイルのeCsvの部分でエクスポートされたcsvファイルのデータの大部分が0に置き換えられてしまう(添付画像参照)
②①が解決し二次元配列への格納ができたとして、一致したデータの行数、列数をどう取得すればいいのかわからない

最終的にはこれを400×400のcsvファイルで利用したいと考えています。
まだまだ初学者ですので、お知恵を貸していただけると助かります。

###添付画像
元ファイル
再出力ファイル

###開発環境
Sublime Text 3
MinGW g++

該当のソースコード

C++

1#include <iostream> 2#include <fstream> 3#include <sstream> 4#include <string> 5 6#define MAP_HEIGHT 10 7#define MAP_WIDTH 10 8 9using namespace std; 10 11int m_Map[10][10]; // csvデータ格納 12 13int stoi(string str){ // stoi関数の定義 14 int ret; 15 stringstream ss; 16 ss << str; 17 ss >> ret; 18 return ret; 19} 20 21void iCsv(){ // csvファイルのインポート 22 23 ifstream ifs("Original/Test.csv"); 24 string line; 25 int i; 26 27 i = 0; 28 29 while(getline(ifs, line)){ 30 31 string token = ","; 32 istringstream stream(line); 33 34 while(getline(stream, token)){ 35 m_Map[i/MAP_HEIGHT][i%MAP_WIDTH] = stoi(token.c_str()); 36 i++; 37 } 38 39 } 40 41} 42 43void eCsv(){ //正しく入力されたかどうか確認 44 ofstream ofs("Converted/Test.csv");//ファイルの出力ストリーム 45 for (int i = 0; i < MAP_HEIGHT; i++){ 46 47 for (int j = 0; j < MAP_WIDTH; j++){ 48 int num = i*j; 49 ofs<<(int)m_Map[num / MAP_HEIGHT][num% MAP_WIDTH]<<"," ; 50 } 51 52 ofs << endl; 53 54 } 55 56 ofs.close(); 57 58} 59 60int main(){ 61 iCsv(); 62 eCsv(); 63 64 return 0; 65}

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

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

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

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

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

yumetodo

2018/08/16 15:14

そもそもstoi関数は自作しないでもC++11にあります。普通にstd::stoiとしてみてください。
退会済みユーザー

退会済みユーザー

2018/08/17 08:57

ご指摘ありがとうございます。私も最初はそのようにしていたのですが、エラーが発生してしまったため定義しています。私の環境のC++のバージョンが古いのかもしれません・・・。
yumetodo

2018/08/17 11:39

お使いの環境を追記してください。gcc/clangなら-std=c++11をつければ利用できるはずです。
退会済みユーザー

退会済みユーザー

2018/08/17 15:04

環境追記しました。コンパイラはMinGW,g++です。
yumetodo

2018/08/17 16:36

だいぶ前のmingw gccでも-std=c++11は使えるはずなのでどうぞ
退会済みユーザー

退会済みユーザー

2018/08/19 06:12

ありがとうございます。分かりました、やってみようと思います。
guest

回答2

0

C++

1#include <iostream> 2#include <string> 3#include <fstream> 4 5int main() { 6 using namespace std; 7 ifstream stream("test.csv"); 8 string line; 9 int data[10][10]; 10 const string delim = ","; 11 12 int row = 0; 13 int col; 14 while ( getline(stream, line) ) { 15 col = 0; 16 // delimを区切り文字として切り分け、intに変換してdata[][]に格納する 17 for ( string::size_type spos, epos = 0; 18 (spos = line.find_first_not_of(delim, epos)) != string::npos;) { 19 string token = line.substr(spos,(epos = line.find_first_of(delim, spos))-spos); 20 data[row][col++] = stoi(token); 21 } 22 ++row; 23 } 24 25 // よめたかな? 26 for ( row = 0; row < 10; ++row ) { 27 for ( col = 0; col < 10; ++col ) { 28 cout << data[row][col] << " "; 29 } 30 cout << endl; 31 } 32}

コレ↑にtest.csv↓を食わせてみた

0,1,2,3,4,5,6,7,8,9 1,2,3,4,5,6,7,8,9,0 2,3,4,5,6,7,8,9,0,1 3,4,5,6,7,8,9,0,1,2 4,5,6,7,8,9,0,1,2,3 5,6,7,8,9,0,1,2,3,4 6,7,8,9,0,1,2,3,4,5 7,8,9,0,1,2,3,4,5,6 8,9,0,1,2,3,4,5,6,7 9,0,1,2,3,4,5,6,7,8

実行結果
0 1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9 0
2 3 4 5 6 7 8 9 0 1
3 4 5 6 7 8 9 0 1 2
4 5 6 7 8 9 0 1 2 3
5 6 7 8 9 0 1 2 3 4
6 7 8 9 0 1 2 3 4 5
7 8 9 0 1 2 3 4 5 6
8 9 0 1 2 3 4 5 6 7
9 0 1 2 3 4 5 6 7 8

投稿2018/08/17 23:01

episteme

総合スコア16612

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

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

0

ベストアンサー

こんばんは。

まだ初学者ということなので、まずはプログラムがうまく動かない場合の調べ方をお伝えします。

想定した挙動が得られない場合は、必ず「デバッグ」をしてみましょう。
一行ずつプログラムを動かしていく(ステップ実行といいます)と、どこでデータが0に書き換えられているのかがきっと見つかります。
どのような開発環境かは存じ上げませんが、大体はデバッグ実行中に変数の値を確認できます。
「ウォッチ」と呼ばれる機能です。
これをちゃんと使えば、どこに問題があるかがきっと見つかります。

このように短いソースコードなら、頑張れば必ずどこが悪いかがわかるはずです。

ちなみに、今回は関数のリファレンスと型変換がポイントになると思います。
関数のリファレンスとは、関数の引数と戻り値がどのようになっているか、という情報です。
プログラムをする上で、絶対に切り離せない概念です。
関数を使う際は、必ずその関数のリファレンスを確認してください。
C++において変数の型は非常に重要ですので、この機にきっちりと身につけましょう。
(なぜ0になるのだろう、という疑問があると思いますが、これはこの変数の型に起因しています。)
それと、よく使う関数は誰かが作ってくれていたり、標準であったりもしますよ。
プログラムは効率よく、楽できるところは楽をするようにしていきましょう。

追記)
②の解答ができていませんでした。
取得した結果をどのように出力するのかがわかりかねますが、一致している個所を探すのは簡単です。
行および列でループ処理を組んで、その中でif文で比較してやればよいだけです。
行数や列数は変数をループごとにカウントアップ(インクリメント)してあげれば、取得できますね。

投稿2018/08/16 12:32

編集2018/08/16 12:49
BellBlue

総合スコア17

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

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

退会済みユーザー

退会済みユーザー

2018/08/17 13:47 編集

回答ありがとうございます。自分で調べたり、修正した結果、1行だけ正しく出力され、残りはみんな0になる、という状況になってしまいました。使用している環境はコードエディタにSublime Text、コンパイラにMinGWのg++、といった状況なのですが、使いこなせていない部分が多く、ステップ実行のやり方がよくわかりません・・・申し訳ないのですが、更に詳しいご指摘をいただきたいです。よろしくお願い致します。 追記)修正箇所について eCsv内、jについてのfor文の部分を、 for (int j = 0; j < MAP_WIDTH; j++){ ofs << (int)m_Map[i][j] << ","; } としました。
BellBlue

2018/08/17 23:21

お疲れ様です。 アウトプットは正しく動きそうになりましたね。 コンパイルするときのコマンドに、オプションとして -g を加えてください。 これによってできあがるexeには、「デバッグ情報」が付加されます。 このデバッグ情報を解析して表示してくれるのが「デバッガ」です。 MinGWをお使いとのことですので、「gdb」というデバッガを使用することになります。 次に、デバッガをどうやって起動するかという点です。 もちろんコマンドを叩いて動かせますが、色々と不便です。 そこで、お使いのエディタからデバッガを起動してやりましょう。 ただ、申し訳ないことに私はsublime textを使ったことがないので、具体的にご説明できません、、 お使いのエディタがgdbに標準対応しているかどうか調べて、対応していないならプラグインを入れて、デバッガを動かしてください。 これでステップ実行できるはずです。 最後に。 最新のソースは、一行目だけ正しく出力できているわけではないのでご注意ください。 偶然、そのように見えているだけです。 プログラミングでよく陥る罠です。。 「ここが悪いはず!」と思ってしまうと、他に注意が向かず、解決に時間を費やしてしまいます。 そして、どうしてもわからなかったら、インプットのCSVの値を不規則にしてみてください。
退会済みユーザー

退会済みユーザー

2018/08/18 07:38

返信ありがとうございます。gdbはプラグインがある、とのことなので、早速調べながらインストールしようと思います。 また、出力についてですが、本来1列目に並んでいる数字が1行目に並んでいるのではないか、と考えたのですが、合っているでしょうか。とすると、これは入力時に何かしらのエラーが起きている、と考えるのが妥当…そう考えると、iCsvのgetline関数あたりに原因があるのでしょうか?
BellBlue

2018/08/18 11:42

もう解決されたかもしれませんが… 仰るとおりで、getline関数を調べていただければ原因は見つけられると思います。
退会済みユーザー

退会済みユーザー

2018/08/19 06:10

ありがとうございます。調べてみたところ、なんとかできそうです。丁寧なご教示ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問