2013-04-21 93 views
3

我的任務是微不足道的 - 我只需要解析這樣的文件:在C++上迭代ini文件,可能使用boost :: property_tree :: ptree?

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 entries in section

的問題是 - 什麼是上面寫上的C#代碼模擬的最簡單方法C++?

+1

_Of course_有可能迭代ptree,實際上它是微不足道的,因爲我的答案現在顯示(更新)(注意:程序選項!=屬性樹) – sehe 2013-04-21 20:13:18

回答

18

直接回答你的問題:當然迭代屬性樹是可能的。事實上,它是微不足道:

#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 

我以前也寫過使用非常全功能的ini文件解析器:

它支持註釋(單行和塊),引號,轉義等。

(作爲獎勵,它可選地記錄所有解析元素的確切來源位置,這是該問題的主題)。

儘管如此,我想我會推薦Boost Property Tree。

+0

謝謝,我能夠迭代。但由於某些原因,值不會被打印。即我確實只能看到[Cat1] [Cat_2] [Cat_3]作爲輸出,沒有「name1」「name2」等。稍後我會試着解決這個問題,但如果您知道解決方案,我將非常感謝您的幫助:) – javapowered 2013-04-21 20:51:33

+0

「不過爲了你的目的,我想我會推薦Boost Property Tree。」 - 我不明白你推薦什麼。你是否建議不要使用'ini_parser'?你是用'xml'而不是'ini'來推薦?或者是什麼? – javapowered 2013-04-21 20:55:00

+0

@javapowered你知道,我停在那裏,因爲你要求。當然,您也可以打印這些值。我現在添加了它 – sehe 2013-04-21 20:56:27

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++標準庫,它是開放的說法,這將是一個有點迂迴的解決方案。另一種可能性是comment_iterator跳過一行的剩餘部分,從指定的註釋分隔符開始。我不喜歡那樣,但在某些方面可能更簡單。

請注意,我們真正寫在這裏的唯一代碼是從文件中讀取一個單一條目到pairistream_iterator處理幾乎所有的東西。因此,在編寫函數的直接類比時幾乎沒有真正的意義 - 我們只是從迭代器初始化映射,然後就完成了。