user1705329
user1705329

Reputation: 43

How to split a string into different datatypes in C++

I have the following problem: I have an input string that looks something like this: string s ="87635+23754*ar+ar*var*0.895+(ar-var)+ar*ar+var*var";

I want to split this string and execute each operation i.e I want to read in all the values, perform the mathematical operations and output the final answer in C++. How do I do it? getline command can split only one type of delimiter. How do I solve this problem?

Thanks

Nita

Upvotes: 2

Views: 2070

Answers (3)

Jonathan Wakely
Jonathan Wakely

Reputation: 171263

The "correct" answer is to write a parser for your mini-language, but it might be simpler to use string::find_first_of and/or string::find_first_not_of to tokenize it into numbers, operators and named variables

Upvotes: 2

cmeub
cmeub

Reputation: 517

You must write a parser. Don't be scared of the "correct" solution, it's correct for a good reason; it works. The shortcuts offered by others won't make your task any easier.

I have included a basic solution that you can use as a starting point. You should build test cases to make sure it is correct and handle error cases more thoroughly.

Hopefully by studying this code you will get the general idea of a recursive decent parser. We split up the parsing problem by using separate functions for the different levels of operator precedence. These functions call each other in a top down fashion, making this type of parser easier to understand.

I have coded it in such a way as to be brief. If you believe 'goto' is evil, use a while loop instead. Furthermore, convert the parsing functions into a Parser class to get rid of the global variables.

Good luck and happy parsing :)

    #include <string>
    #include <map>
    #include <iostream>
    #include <sstream>
    using namespace std;

    stringstream ss;
    map<string,double> variables;
    string err_string = "";

    double parse_add_exp();

    int main()
    {
        // get the expression and variables
        ss << "87635+23754*ar+ar*var*0.895+(ar-var)+ar*ar+var*var";
        variables["ar"] = -4.5;
        variables["var"] = 141.26f;
        try
        {
            // calculate the result
            double result = parse_add_exp();
            if( result == INFINITY )
                cout<<"Runtime error: Division by zero"<<endl;
            else
                cout<<"Result = "<<result<<endl; // prints 'Result = 1.95143'
        }
        catch (const char * error)
        {
            cout<<"Invalid expression: "<<error<<endl;
        }
        return 0;
    }
    double parse_number()
    {
        double f;
        if( !(ss>>f) )
            throw "Expected number";
        return f;
    }
    double parse_operand()
    {
        string var("");
        while( isalpha(ss.peek()) )
            var += ss.get();
        if( !var.size() )
            return parse_number();
        if( variables.find(var) == variables.end() )
            throw "Variable is undefined";
        return variables[var];
    }
    double parse_parenthesis()
    {
        if( ss.peek() != '(' )
            return parse_operand();
        ss.get();
        double f = parse_add_exp();
        if( ss.get() != ')' )
            throw "Expected closing parenthesis";
        return f;
    }
    double parse_mul_exp()
    {
        double product = parse_parenthesis();
    PEEKOP:
        switch( ss.peek() )
        {
            case '*': ss.get(); product *= parse_parenthesis(); goto PEEKOP;
            case '/': ss.get(); product /= parse_parenthesis(); goto PEEKOP;
            default: return product;
        }
    }
    double parse_add_exp()
    {
        double sum = parse_mul_exp();
    PEEKOP:
        switch( ss.peek() )
        {
            case '+': ss.get(); sum += parse_mul_exp(); goto PEEKOP;
            case '-': ss.get(); sum -= parse_mul_exp(); goto PEEKOP;
            default: return sum;
        }
    }

Upvotes: 1

chrert
chrert

Reputation: 462

Take a look at std::stringstream. You can put a string into the stream and read from it just like from std::cin!

For example:

#include <iostream>
#include <sstream>

int main()
{
    std::stringstream stream(std::stringstream::in | std::stringstream::out);
    stream << "22+2";

    int operand1, operand2;
    char op;

    stream >> operand1;
    stream >> op;
    stream >> operand2;

    std::cout << operand1 << " " << op << " " << operand2 << std::endl;

    return 0;
}

For a more complex example look at the dc-clone I did a while ago: gist.github.com/ae6ebe58a286d6cfd847. Especially look at the lines 467-522 (in main).

Upvotes: 1

Related Questions