Parsing this kind of thing is fairly straightforward (though tedious) with recursive descent techniques. The idea is to separate the language being parsed into logical units, then write a function to parse each of those units.
If we figure in the example "|1,2,3,4,15|(1->2),(3->2),(4->15)|" that the whole string is a "polygon", we'd write parsePolygon(), which would look something like this:
void parsePolygon (Buffer& b)
{
parseVertices (b);
parseEdges (b);
}
Let's assume Buffer is a class that runs through your string. You'll need two basic operations: peek at the next character without consuming it, and consume the next character.
parseVertices might look like this:
void parseVertices (Buffer& b)
{
if (b.peek() != '|') { /* error */ }
b.consume (); // burn the '|'
parseVertexList (b);
if (b.peek() != '|') { /* error */ }
b.consume (); // burn the '|'
}
You'd want to handle errors much better, obviously. If the stream encounters any error it needs to pass the error code up the callstack or throw an exception.
Two more examples... parseVertexList and parseNumber might look like this:
void parseVertexList (Buffer& b)
{
addVertex (parseNumber (b));
while (b.peek() == ',')
{
b.consume (); // eat the comma
addVertex (parseNumber (b));
}
}
int parseNumber (Buffer& b)
{
char accum[80] = { '0' }; // sensible default in case of failure
int accumPos = 0;
while (isDigit (b.peek())
{
accum[accumPos++] = b.consume();
}
return atoi(accum);
}
This is all very quick and dirty, but hopefully it gives you an idea how the technique works. You can intermix your handling with your parsing as shown above, where the parseVertexList function actually does the addVertex calls for you.
I think this is really one of the simplest methods of manual parsing. Ideally we'd always be able to use generated parsers like boost spirit or pyparsing or lex/yacc, but life isn't always that good, especially for homework.
Also I suppose it's worth noting that the above technique can be a lot of overkill for some parsing situations.