2013-04-21 95 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处理几乎所有的东西。因此,在编写函数的直接类比时几乎没有真正的意义 - 我们只是从迭代器初始化映射,然后就完成了。