tags:

views:

1182

answers:

8

Hi,

I'm a newbie looking for a fast and easy way to parse a text file in C or C++ (wxWidgets)

The file will look something like this (A main category with "sub-objects") which will appear in a list box

[CategoryA]

[SubCat]

    Str1 = Test 

    Str2 = Description  

[SubCat] [End]

[SubCat]

    Str1 = Othertest
...

[CategoryA] [End]

Any suggestions?

+6  A: 

Sounds like you want to parse a file that's pretty close to an ini file.

There's at least a few INI parser libraries out there: minIni, iniParser, libini, for instance.

Mark Rushakoff
A: 

How about trying to make a simple XML file? There are plenty of libraries that can help you read it, and the added bonus is that a lot of other programs/languages can read it too.

kkaploon
I have found the overhead of not necessarily the parsing but the binding of xml files to the data not worth the effort for simple configuration files. If you have something that creates the bindings it is a different matter.
Harald Scheirich
A: 

It looks more straightforward to implement your own parser than to try to adapt an existing one you are unfamiliar with.

Your structure seems - from your example - to be line-based. This makes parsing it easy.

It generally makes sense to load your file into a tree, and then walk around it as necessary.

Will
+1  A: 

On Windows only, GetPrivateProfileSection does this. It's deprecated in favor of the registry but it's still here and it still works.

Emmanuel Caradec
A: 

Thanks for all replies,

XML is not an option and I cannot use any parser libraries. I'd need a solution with 'general' C/C++ code and maybe WIN API functions; 'GetPrivateProfileSection', however, cannot handle subsections? Any code samples?

Daniel
+1  A: 

It should be fairly easy to write your own parser for this if you use streams. You can read a file using an std::ifstream:

std::ifstream ifs("filename.ext");
if(!ifs.good()) throw my_exceptions("cannot open file");
read_file(ifs);

Since it seems line-oriented, you would then first read lines, and then process these:

void read_file(std::istream& is) 
{
  for(;;) {
    std::string line;
    std::getline(is, line);
    if(!is) break;
    std::istringstream iss(line);
    // read from iss 
  }
  if(!is.eof()) throw my_exceptions("error reading file");
}

For the actual parsing, you could 1) first peek at the first character. If that's a [, opo it from the stream, and use std::getline(is,identifier,']') to read whatever is within '[' and ']'. If it isn't a [, use std::getline(is, key, '=') to read the left side of a key-value pair, and then std::getline(is, value) to read the right side.

Note: Stream input, unfortunately, is usually not exactly lightning fast. (This doesn't have to be that way, but in practice this often is.) However, it is really easy to do and it is fairly easy to do it right, once you know a very few patterns to work with its peculiarities (like if(strm.good()) not being the same as if(strm) and not being the opposite of if(strm.bad()) and a few other things you'll have to get used to). For something as performance-critical (har har!) as reading an ini file from disk, it should be fast enough in 999,999 out of 1,000,000 cases.

sbi
+1  A: 

You may want to try Boost.Program_Options. However it has slightly different formatting. More close to INI files. Subcategories are done like this:

[CategoryA]
Option = Data

[CategoryB.Subcategory1]
Option = Data

[CategoryB.Subcategory2]
Option = Data

Also it has some other features so it is actually very useful IMO.

Adam Badura
A: 

If you're using wxWidgets I would consider wxFileConfig. I'm not using wxWidgets, but the class seems to support categories with sub-categories.

larsm