1

i have a problem and i think the solution might be pretty easy but im kinda stuck. I have some kind of config file wich im trying to parse in c++ to get some important values.

It looks like this:

info size=32 bold=0 italic=0 unicode=1 stretchH=100 smooth=1 aa=1 padding=0,0,0,0
common lineHeight=32 base=27 scaleW=1024 scaleH=28 pages=1 packed=0 alphaChnl=1
chars count=74
char id=32 x=837 y=15 width=3 height=1 xoffset=-1 yoffset=31 xadvance=8 page=0 chnl=15
char id=33 x=802 y=0 width=4 height=19 xoffset=2 yoffset=8 xadvance=8 page=0 chnl=15
char id=35 x=292 y=0 width=17 height=19 xoffset=0 yoffset=8 xadvance=16 page=0 chnl=15
char id=37 x=177 y=0 width=19 height=19 xoffset=-1 yoffset=8 xadvance=17 page=0 chnl=15
char id=38 x=216 y=0 width=18 height=19 xoffset=0 yoffset=8 xadvance=18 page=0 chnl=15

Info, common and chars a basic/global values. Every char line should be saved in an array (or vector) of structs with a similar format (x, y, height, offsetX, offsetY ...)

Now i've tried getline() for example to get every line one by one and then make an istringstream with these lines to "search" those lines for the values i need. Its worth noticing that iam not needing all those values i need a way to just save the one i need for every line.

Thanks in advance for any help here!

puelo
  • 5,464
  • 2
  • 34
  • 62

3 Answers3

2

Each line is prefixed by the type of object.
So your reader should read the first word off and then decide what object to read.

std::ifstream  file("data.txt");
std::string    type;
while(file >> type)
{
         if (type == "info")    { readInfo(file);}
    else if (type == "common")  { readCommon(file);}
    else if (type == "chars")   { readChars(file);}
    else if (type == "char")    { readChar(file);}
}

For each type of object you need to define a structure to hold the data.

// char id=32 x=837 y=15 width=3 height=1 xoffset=-1 yoffset=31 xadvance=8 page=0 chnl=15
struct CharData
{
    int   id;
    int   x;
    int   y;
    int   width;
    int   height;
    int   xoffset;
    int   yoffset;
    int   xadvance;
    int   page;
    int   chnl;
};

Now you have to define a method to read the data. In C++ we use operator>> to read data from a stream.

std::istream& operator>>(std::istream& stream, CharData& data)
{
    // All the data is on one line.
    // So read the whole line (including the '\n')
    std::string        line;
    std::getline(stream, line);

    // convert the single line into a stream for parsing.
    // One line one object just makes it easier to handle errors this way.
    std::stringstream  linestream(line);

    // Assume the prefix type information has already been read (now looks like this)
    // id=32 x=837 y=15 width=3 height=1 xoffset=-1 yoffset=31 xadvance=8 page=0 chnl=15
    std::string   command;
    while(linestream >> command) // This reads one space separated command from the line.
    {
             if (command.substr(0,3) == "id=")        {data.id       = atoi(&command[3]);}
        else if (command.substr(0,2) == "x=")         {data.x        = atoi(&command[2]);}
        else if (command.substr(0,2) == "y=")         {data.y        = atoi(&command[2]);}
        else if (command.substr(0,6) == "width=")     {data.width    = atoi(&command[6]);}
        else if (command.substr(0,7) == "height=")    {data.height   = atoi(&command[7]);}
        else if (command.substr(0,8) == "xoffset=")   {data.xoffset  = atoi(&command[8]);}
        else if (command.substr(0,8) == "yoffset=")   {data.yoffset  = atoi(&command[8]);}
        else if (command.substr(0,9) == "xadvance=")  {data.xadvance = atoi(&command[9]);}
        else if (command.substr(0,5) == "page=")      {data.page     = atoi(&command[5]);}
        else if (command.substr(0,5) == "chnl=")      {data.chnl     = atoi(&command[5]);}
    }
    return stream;
}

Repeat the processes for the other types you need to read. Then writting the read commands becomes simple:

std::vector<CharData>    charVector;
void readChar(std::istream& stream)
{
    CharData     data;
    stream >> data;               // read the object from the stream
                                  // This uses the `operator>>` we just defined above.

    charVector.push_back(data);   // put the data item into a vector.
}

Repeat the processes for the other types.

Martin York
  • 257,169
  • 86
  • 333
  • 562
  • shouldn't the operator read only the type? the rest of the variables should be read in the type dependant functions – Gir Aug 12 '12 at 16:00
  • Minor apparent typo: unless I've misinterpreted something, all the instances of `itoa` above are really intended to be `atoi`. – Jerry Coffin Aug 12 '12 at 20:42
  • Works like a charm - one thing to change, apart from the thing Jerry Coffin was noticing, though. The readChar methods need the stream by reference, copying is not allowed: readChar(std::istream& stream) – puelo Aug 12 '12 at 21:32
0

There is

important_value=str_from_getline.find(what_to_find);

important_value is a size_t and has the starting point of what you seek in getline() string

huseyin tugrul buyukisik
  • 11,469
  • 4
  • 45
  • 97
0

Try using strtok or a c++ regex library

Gir
  • 839
  • 5
  • 11
  • No don't. strtok() is an abomination of C. There are much better techniques in C++. – Martin York Aug 12 '12 at 15:58
  • Well the worst thing it uses C-Strings. Next it mutates the string (so it is not a real function). Next it depends on the mutations to keep working each time it is called. – Martin York Aug 12 '12 at 16:05
  • See: http://stackoverflow.com/questions/8705844/need-to-know-when-no-data-appears-between-two-token-separators-using-strtok – Martin York Aug 12 '12 at 16:08