2

次の問題があります: 次のような入力文字列があります。

この文字列を分割し、各操作を実行したい。つまり、すべての値を読み込み、数学演算を実行し、最終的な答えを C++ で出力したい。どうすればいいのですか?getline コマンドで分割できる区切り文字は 1 種類だけです。この問題を解決するにはどうすればよいですか?

ありがとう

ニタ

4

3 に答える 3

2

「正しい」答えは、ミニ言語用のパーサーを作成することですが、それを使用したり、数値、演算子、名前付き変数にトークン化しstring::find_first_ofたりする方が簡単かもしれませんstring::find_first_not_of

于 2012-10-18T17:09:20.580 に答える
1

パーサーを作成する必要があります。「正しい」解決策を恐れないでください。それには正当な理由があります。できます。他の人が提供するショートカットは、あなたのタスクを簡単にするものではありません。

出発点として使用できる基本的なソリューションを含めました。テスト ケースを作成して、それが正しいことを確認し、エラー ケースをより徹底的に処理する必要があります。

願わくば、このコードを勉強することで、再帰的な適切なパーサーの一般的なアイデアを得ることができます。さまざまなレベルの演算子の優先順位に個別の関数を使用して、解析の問題を分割します。これらの関数はトップダウン方式で相互に呼び出し、このタイプのパーサーを理解しやすくします。

簡潔になるようにコーディングしました。「goto」が悪だと思う場合は、代わりに while ループを使用してください。さらに、解析関数を Parser クラスに変換して、グローバル変数を取り除きます。

幸運と幸せな解析:)

    #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;
        }
    }
于 2012-10-18T19:45:32.893 に答える
1

std::stringstreamを見てください。std::cin と同じように、ストリームに文字列を入れて読み取ることができます。

例えば:

#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;
}

より複雑な例については、私が少し前に行ったdc-cloneを見てください: gist.github.com/ae6ebe58a286d6cfd847。特に 467 ~ 522 行 (メイン) を見てください。

于 2012-10-18T17:15:16.567 に答える