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

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

ただいまの
回答率

90.99%

  • C++

    2939questions

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

C++によるテキストファイルからのパラメータ読み込みの方法について

解決済

回答 4

投稿

  • 評価
  • クリップ 0
  • VIEW 480

oknd1

score 9

C++を用いて配列を含む、パラメータが保存されたテキストファイルを読み込む処理を行いたいと思っています。
具体的には、例えば以下のようなファイル

#Setting parameters
#Set Value1
Value1 = 1
#Set Value2
Value2 = 2.0
#Set Value3
Value3 = 3.0 
#Set Array1
Array1 = 1.0 2.0 3.0
#Set Array2
Array2 = 4.0 5.0 6.0


のようなファイルが有ったときに, #のあるコメント行は読み飛ばして, intやdouble型の数値Value1,Value2,Value3と配列Array1,Array2を読み込めるようにしたいと思っています。

色々検索していて見つかった方法の一つとして, 配列がなく一つの行に一つの数値があるだけならば

f = fopen("parameter.txt", "r");
while(fgets(line, 256, f) != NULL){
    if((line[0] == '#') || (!strcmp(line, "\n")))
    ;
  else{
sscanf(line, "%s %s %s\n", &name, &equal, &value);
    if((!strcmp(name, "Value1"))
.....


のようにして各行読んでwhileやifを使えばコメントの読み飛ばしやValue1やValue2の識別も可能だと思うのですが, Array1のように空白などのセパレータでわけられた複数の数値を配列として一括に読み込む機能をどうつければ良いのかわからず困っております。また, Array1に入る数値の個数も不明な状態で実行できるようにしたいと思っています。

何か, 良い方法はあるでしょうか。お知恵を貸していただければと思います。
よろしくお願いいたします。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

checkベストアンサー

+2

こんにちは。

取り敢えず、標準入力から読むだけなら以下のイメージでできます。
読み取ったものを変数に入れる場合は、何をどのようにしまうのかよく検討が必要です。
とりあえず動的配列(実行中に要素数が変わる配列)にはstd::vectorを使うのが常道です。

#include <iostream>
#include <string>
#include <sstream>

int main()
{
    std::string line;
    while(std::getline(std::cin, line))
    {
        if (line[0] == '#')
    continue;
        if (line.find('=') == std::string::npos)
    continue;

        std::stringstream ss(line);
        std::string name;
        ss >> name;
        ss.ignore(line.size(), '=');
        std::cout << name << " = ";
        double temp;
        while(ss >> temp)
        {
            std::cout << temp << " ";
        }
        std::cout << "\n";
    }
}


wandboxサンプル

たぶん、初めて見る関数が多数あると思いますが、std::で始まるものは標準ライブラリですので検索すると解説が直ぐに見つかりますので、参考にされて下さい。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/26 01:56

    Chironian様

    ありがとうございます。調べながら見てみてなんとなくですがわかりました。
    ご指摘の通りstd::vectorを用いるのがセオリーのようなのでそのようにしようと思います。
    とりあえず、上げていただいたコードをベースに試してみようと思います。

    キャンセル

+2

1.コメントをスキップして一行取り出す関数を作る

bool ReadLine(string & readline)
{
    while(getline( cin, readline )){
        if(readline.find_first_of("#") == string::npos){
            break;
        }
    }
    return !cin.eof();    // ファイル読み込みが終了すると偽が返る
}


のようなもの・・・・

2.KSwordOfHasteさんの回答にあるように数値を1つづ切り出す関数を作る。(返り値は読み込んだ数値の数・・・int mysplit(std::string & line, std::vector<double> value)・・・自前のsscanf()のようなもの)

3.vectorを処理する・・・

とか、どうでしょう?
「追記」
エラー処理はまったく考えていません。読み込むデータが自前でないのなら、空行の処理や数値がなかった場合など対応が必要と思います。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/26 01:57

    cateye様

    ありがとうございます。
    2., 3.の方法で試してみようと思います。
    ちなみにデータは自前なのである程度やりやすいようにはデータのフォーマットを変えることもできます。

    キャンセル

+1

多くの言語で文字列クラスに「split=区切り文字を指定した分割」機能がついてたりしますが、C++のstd::stringにはそれがないのだろうかと思い調べてみるとなさそうだと思いました。

一次資料でなくてすみませんが自分は以下などいくつかのサイトでそうなっているのをみてそう思いました。
http://vivi.dyndns.org/tech/cpp/string.html

自分で作るしかないのだとしたら' 'を探しつつ数字部分を切り出してそれを整数へ変換してvectorに詰め、最終的にvectorを返すという感じにすればよいと思います。そうしてsplitを用意しておけば指定されたパラメータの種類によってスカラー値を取るべきパラメータについてはvectorの要素が1であることを確認した上で先頭要素を値とし、配列を取るパラメーターならvectorの値そのものを用いるといった感じにすればよいと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/26 01:53

    KSwordOfHaste様

    ありがとうございます。確かに、std::stringにはそのような機能はないのかと思います。
    地道な方法ではありますが、ご教授の方法を検討してみようと思います。

    キャンセル

+1

皆様ありがとうございました。
とりあえず望んでいたことはできるようになりましたので、備忘録も兼ねてコードを掲載しておきます。

#include <iostream>
#include <string>
#include <stdio.h>
#include <fstream>
#include <sstream>
#include <vector>

using namespace std;

    int main() {
        std::ifstream fin("parameter.txt");

        if (!fin)
            return 1;

        int value1;
        double value2;
        double value2;
        std::vector<double> vec1;
        std::vector<double> vec2;
        double temp;


        std::string line;
        while (std::getline(fin, line))
        {
            if (line[0] == '#')
                continue;
            if (line.find('=') == std::string::npos)
                continue;

            std::stringstream ss(line);
            std::string name;

            ss >> name;
            ss.ignore(line.size(), '=');
            //std::cout << name << " = ";
            if (name == "value1") {
                ss >> value1;
            }
            else if (name == "value2") {
                ss >> value2;
            }
            else if (name == "value3") {
                ss >> lgauss_width;
            }
            else if (name == "array1") {
                while (ss >> temp)
                {
                    vec1.push_back(temp);
                }
            }
            else if (name == "array2") {
                while (ss >> temp)
                {
                    vec2.push_back(temp);
                }
            }

        }



    }

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 90.99%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • C++

    2939questions

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