次の問題があります: 次のような入力文字列があります。
この文字列を分割し、各操作を実行したい。つまり、すべての値を読み込み、数学演算を実行し、最終的な答えを C++ で出力したい。どうすればいいのですか?getline コマンドで分割できる区切り文字は 1 種類だけです。この問題を解決するにはどうすればよいですか?
ありがとう
ニタ
「正しい」答えは、ミニ言語用のパーサーを作成することですが、それを使用したり、数値、演算子、名前付き変数にトークン化しstring::find_first_of
たりする方が簡単かもしれませんstring::find_first_not_of
パーサーを作成する必要があります。「正しい」解決策を恐れないでください。それには正当な理由があります。できます。他の人が提供するショートカットは、あなたのタスクを簡単にするものではありません。
出発点として使用できる基本的なソリューションを含めました。テスト ケースを作成して、それが正しいことを確認し、エラー ケースをより徹底的に処理する必要があります。
願わくば、このコードを勉強することで、再帰的な適切なパーサーの一般的なアイデアを得ることができます。さまざまなレベルの演算子の優先順位に個別の関数を使用して、解析の問題を分割します。これらの関数はトップダウン方式で相互に呼び出し、このタイプのパーサーを理解しやすくします。
簡潔になるようにコーディングしました。「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;
}
}
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 行 (メイン) を見てください。