4

私の仕事は簡単です-そのようなファイルを解析するだけです:

Apple = 1
Orange = 2
XYZ = 3950

しかし、利用可能なキーのセットがわかりません。C# を使用して比較的簡単にこのファイルを解析していたので、ソース コードを示します。

    public static Dictionary<string, string> ReadParametersFromFile(string path)
    {
        string[] linesDirty = File.ReadAllLines(path);
        string[] lines = linesDirty.Where(
            str => !String.IsNullOrWhiteSpace(str) && !str.StartsWith("//")).ToArray();

        var dict = lines.Select(s => s.Split(new char[] { '=' }))
                        .ToDictionary(s => s[0].Trim(), s => s[1].Trim());
        return dict;
    }

ここで、C++ を使用して同じことを行う必要があります。使用することを考えていましたがboost::property_tree::ptree、iniファイルを反復処理できないようです。ini ファイルを読むのは簡単です:

boost::property_tree::ptree pt;
boost::property_tree::ini_parser::read_ini(path, pt);

ただし、それを繰り返すことはできません。この質問を参照してくださいBoost program options - get all entry in section

問題は、上記の C# コードのアナログを C++ で記述する最も簡単な方法は何ですか?

4

2 に答える 2

19

あなたの質問に直接答えるには: もちろん、プロパティ ツリーの反復は可能です。実際、それは些細なことです:

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>

int main()
{
    using boost::property_tree::ptree;
    ptree pt;

    read_ini("input.txt", pt);

    for (auto& section : pt)
    {
        std::cout << '[' << section.first << "]\n";
        for (auto& key : section.second)
            std::cout << key.first << "=" << key.second.get_value<std::string>() << "\n";
    }
}

これにより、次のような出力が得られます。

[Cat1]
name1=100 #skipped
name2=200 \#not \\skipped
name3=dhfj dhjgfd
[Cat_2]
UsagePage=9
Usage=19
Offset=0x1204
[Cat_3]
UsagePage=12
Usage=39
Offset=0x12304

以前、 を使用して非常にフル機能の Inifile パーサーを作成しました。

コメント (1 行とブロック)、引用符、エスケープなどをサポートしています。

(おまけとして、オプションで、その質問の主題であったすべての解析された要素の正確なソースの場所を記録します)。

ただし、目的のためには、Boost Property Tree をお勧めします。

于 2013-04-21T19:58:09.837 に答える
0

とりあえず、問題を少し単純化して、コメントのロジックを省略しました (とにかく壊れているように見えます)。

#include <map>
#include <fstream>
#include <iostream>
#include <string>

typedef std::pair<std::string, std::string> entry;

// This isn't officially allowed (it's an overload, not a specialization) but is
// fine with every compiler of which I'm aware.
namespace std {
std::istream &operator>>(std::istream &is,  entry &d) { 
    std::getline(is, d.first, '=');
    std::getline(is, d.second);
    return is;
}
}

int main() {
    // open an input file.
    std::ifstream in("myfile.ini");

    // read the file into our map:
    std::map<std::string, std::string> dict((std::istream_iterator<entry>(in)),
                                            std::istream_iterator<entry>());

    // Show what we read:
    for (entry const &e : dict) 
        std::cout << "Key: " << e.first << "\tvalue: " << e.second << "\n";
}

個人的には、コメント スキップをフィルタリング ストリーム バッファーとして記述すると思いますが、C++ 標準ライブラリに慣れていない人にとっては、多少回りくどい解決策であるという議論に開かれています。もう 1 つの可能性はcomment_iterator、指定されたコメント区切り文字から始まる、行の残りをスキップする です。私もそれは好きではありませんが、おそらくいくつかの点でより単純です。

ここで実際に記述する唯一のコードは、ファイルから単一のエントリをpair. そこistream_iteratorからほとんどすべてを処理します。そのため、関数の直接的な類似物を作成してもほとんど意味がありません。イテレータからマップを初期化するだけで完了です。

于 2013-04-21T19:57:41.947 に答える