Iterating over an ini file in C ++, possibly using boost :: property_tree :: ptree?

My task is trivial - I just need to parse such a file:

Apple = 1 Orange = 2 XYZ = 3950 

But I do not know the set of available keys. I pretty easily parsed this file using C # to demonstrate the source code:

  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; } 

Now I just need to do the same using C ++. I was thinking of using boost::property_tree::ptree , but it seems like I just can't boost::property_tree::ptree over the ini file. Easy to read ini file:

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

But it is impossible to rename it; refer to this question. Improve the program settings - get all the entries in the section.

The question is, what is the easiest way to write an analogue of the C # code above in C ++?

+3
c ++ boost
Apr 21 '13 at 19:28
source share
2 answers

To answer your question directly: of course, you can iterate through the property tree . This is actually trivial:

 #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"; } } 

The result is the conclusion:

 [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 



I wrote a very full-featured Inifile parser using boost-spirit before:

  • Cross-platform way to get the line number of the INI file in which this parameter is specified

It supports comments (single line and block), quotation marks, screens, etc.

(as a bonus, he probably records the exact location of the source of all analyzed elements, which was the subject of this question).

For your purpose, however, I think I would recomment the Boost Property Tree.

+18
Apr 21 '13 at 19:58
source share

At the moment, I have simplified the problem a bit by leaving the comment logic (which in any case looks broken).

 #include <map> #include <fstream> #include <iostream> #include <string> typedef std::pair<std::string, std::string> entry; // This isn't officially allowed (it 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"; } 

Personally, I think that I will write the omission of the comment as a filter of the filtering stream, but for those who are not familiar with the standard C ++ library, it is open for an argument, which will be a somewhat roundabout solution. Another option would be comment_iterator , which skips the rest of the line, starting with the designated comment delimiter. I don’t like it either, but it’s probably easier in some respects.

Please note that the only code that we really write here is to read one, one record from the file in pair . istream_iterator handles almost everything. Thus, it makes little sense to write a direct analog of your function - we just initialize the map from iterators, and we are done.

0
Apr 21 '13 at 19:57
source share



All Articles