13

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?

Glen
  • 21,816
  • 3
  • 61
  • 76

9 Answers9

16

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
  • 249,864
  • 45
  • 407
  • 398
15

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 [, pop 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
  • 219,715
  • 46
  • 258
  • 445
  • 3
    Three years later, but a very informative answer. I'm quite new to file streams and you supplied all the information I'd need to make a basic parser without any additional libraries (Mostly I like the whole getline argument to get a string between specific characters). I wish I could give more than one +1. – Ashley Davies Nov 02 '12 at 00:33
9

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
  • 5,069
  • 1
  • 35
  • 70
3

Try Configurator. It's easy-to-use and flexible C++ library for configuration file parsing (from simplest INI to complex files with arbitrary nesting and semantic checking). Header-only and cross-platform. Uses Boost C++ libraries.

See: http://opensource.dshevchenko.biz/configurator

Denis Shevchenko
  • 1,342
  • 2
  • 10
  • 23
1

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
  • 73,905
  • 40
  • 169
  • 246
1

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

Uli Köhler
  • 13,012
  • 16
  • 70
  • 120
Emmanuel Caradec
  • 2,302
  • 1
  • 19
  • 38
0

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.

kostia
  • 6,161
  • 3
  • 19
  • 23
  • 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 Sep 13 '09 at 17:34
0

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

larsmoa
  • 12,604
  • 8
  • 62
  • 85
0

When you are using GTK, you are lucky.

You can use the Glib KeyFile save_to_file and load_from_file.
https://docs.gtk.org/glib/struct.KeyFile.html

Or when using Gtkmm (C++).
See: https://developer-old.gnome.org/glibmm/stable/classGlib_1_1KeyFile.html

Example in C++ with load_from_file:

#include <glibmm.h>
#include <string>

Glib::KeyFile keyfile;
keyfile.load_from_file(file_path);
std::string path = keyfile.get_string("General", "Path");
bool is_enabled = keyfile.get_boolean("General", "IsEnabled");

Saving is as easy as calling save_to_file:

Glib::KeyFile keyfile;
keyfile.set_string("General", "Path", path);
keyfile.set_boolean("General", "IsEnabled", is_enabled);
keyfile.save_to_file(file_path);
Melroy van den Berg
  • 2,697
  • 28
  • 31