Subscribe to Bodom's Universe        RSS Feed
-----

<sstream> and Parsing in C++

Icon Leave Comment
Due to the fact that no one seems to read my blogspot blog, I've decided it may be more contributing to the DIC community if I were to start posting here again.


I wanted to mention something about the <sstream> header file, which I feel is overlooked and rarely seen.

Parsing is one thing people who program in Java and C# take for granted. In C++, it is not so simple as saying myInt.ToString();

This was a problem for me a little while ago, as I needed to be able to convert strings into integers. What ended up being my solution is to in fact create an object that acted like an istream and contained the string i wanted to change, and then just read the stream into an integer. Let me show you what I am talking about.

My most recent project is something along the lines of Maple and Matlab, though it will turn out to be quite simple.
In this project, I have a class called input, whose current declaration looks like so:

#include<string>
#include<vector>
using namespace std;

// input class for each part of an equation, seperated by some sort of operator. (+ = , - etc)
class input
{
private:
	string inp;							// input string to be parsed
	vector<string> vars;				// vector of variables
	double num;							// constant number
	void ParseInput(void);				// Seperates ints and variables
	double toDouble(const string str);  // converts a string into a double

public:
	input(string i);		// Constructor, takes single string as argument
	double get_num(int i);	// Retrieves number
};



I also have the source file input.cpp, which looks like this:
#include<sstream>
#include"input.h"


/// This file contains the implementatioin for the class input ///

/* Public Methods */

// constructor
input::input(string i)
{
	inp = i;
	num = 1;
	ParseInput();
}

// get num method returns number at position i
double input::get_num(int i)
{
	return num;
}

/* Private Methods */

// Parse the data into the vectors, this is only called once!
void input::ParseInput(void)
{
	vector<string> numtemp;
	int n = 0, i = 0, j = 0; // where n is posn in string, i is numtemp vector ref point, and j is vars vector ref point

	// create a new box on the vector to store a number
	numtemp.push_back("");
	vars.push_back("");
	// find all of the numbers
	while (n != inp.size())
	{
		// if we find a number, append it to our string of them
		if (inp.at(n) <= '9' && inp.at(n) >= '0')
		{
			if (vars.at(j) != "")
			{
				vars.push_back("");
				j++;
			}
			numtemp.at(i) += inp.at(n);
			n++;
		}
		// handle decimal points
		else if (inp.at(n) == '.')
		{
			if (vars.at(j) != "")
			{
				vars.push_back("");
				j++;
			}
			numtemp.at(i) += inp.at(n);
			n++;
		}
		// if we find a character
		else
		{
			// add the character to the current variable
			vars.at(j) += inp.at(n);
			if (vars.at(j) != "")
			{
				numtemp.push_back("");
				i++;
			}
			n++;
		}

		// the class for handling equations will handle parsing wrt operators.
	}
	
	// convert the number strings to numbers and multiply them all into num
	for(unsigned int f = 0; f < numtemp.size(); f++)
	{
		num *= toDouble(numtemp.at(f));
	}
}

// toDouble converts a std::string into a double
double input::toDouble(const string str)
{
	if(str != "")
	{
		istringstream iss(str);
		double retval;
		iss >> retval;
		return retval;
	}
	else return 1;
}



Now what I really want to focus on here is the last 10 lines or so, the double input::toDouble(const string str).
What this does is take a string, str and uses it to create an istringstream, iss.

This instringstream can be comparable to any other type of input stream, such as cin, or some random file stream. We can thus assign it's members, some number, to retval
We can do this for any type of data, as we can with normal input streams.

Now here, I know it is safe to not use a try/catch exception here, as this is a private member, and so is the function that calls it. Thus the only time it will ever be used is when str is a double value.

Generally, however, you do want to add some sort of try catch block here:

try
{
	iss >> retval;
}
catch(...)
{
	// do something about it...
}



Note: this may not be a valid try/catch block, I only really use them in C#.

So, I hope that you can use this idea, and a good reference to <sstream> to get some mad parsing done.

Peace out y'all
~Bodom

0 Comments On This Entry

 

January 2022

S M T W T F S
      1
2345678
9101112131415
161718192021 22
23242526272829
3031     

Recent Comments

Search My Blog

17 user(s) viewing

17 Guests
0 member(s)
0 anonymous member(s)