由于项目需要,15年前自己用c++编写了一个简易的公式编辑器,支持+,-,*,/,函数,自定义变量等,非常实用,现在分享给大家.
calculateformula.h
#ifndef CALCULATEFORMULA_H
#define CALCULATEFORMULA_H
#include <functional>
#include <qstring.h>
#include <qstack.h>
#include <QVariant>
class CalculateFormula
{
public:
constexpr static double MATH_PI = 3.14159265358979323846;
using CallbackGetSymbolValue = std::function<double(const QString&, QVariant& value, bool& bOK)>;
CalculateFormula(CallbackGetSymbolValue symbolHandler, QVariant value);
bool Calculate(const QString& strFormula,double& dResult);
QString GetPhrase(const QString& strPhrase,int& newIndex,int& type);
double CalculateValue(double v1,double v2,int type,bool& bOk);
double ToDouble(const QString& variable, bool& bOk);
bool IsHighPriority(int type1,int type2);
bool ProcessStackData(int type);
QString * GetParam(const QString& Formula, int& index,int countParam);
double DoFunction(const QString& funName, const QString& Formula, int& index, bool& bOk);
double CalculateSymbol(const QString& symbol, bool& bOk);
static int GetCharType(const char c);
double Sqrt(QString param [],bool& bOk);
double Pow2(QString param [],bool& bOk);
double Exp(QString param [],bool& bOk);
double Abs(QString param [],bool& bOk);
double Pow(QString param [],bool& bOk);
double IsNull(QString param [],bool& bOk);
double Log(QString param [],bool& bOk);
double Sin(QString param [],bool& bOk);
double Cos(QString param [],bool& bOk);
double Tan(QString param [],bool& bOk);
double Atan(QString param [],bool& bOk);
double Atanr(QString param [],bool& bOk);
public:
CallbackGetSymbolValue OnGetSymbolValue;
private:
QStack<double> m_stkData;
QStack<int> m_stkOperator;
QString m_strErrorMessage="";
QVariant m_objValue;
short arrPriority[7][7]
{
//+,-,*,/,(,),=,
/*+*/ { 0, 0,1,1,2,3,3},
/*-*/ { 0, 0,1,1,2,3,3},
/* * */{-1,-1,0,0,1,2,2},
/* / */{-1,-1,0,0,1,2,2},
/* ( */{-2,-2,-1,-1,0,1,1},
/* )*/{-3,-3,-2,-2,-1,0,0},
/* =*/ {-3,-3,-2,-2,-1,0,0}
};
};
#endif // CALCULATEFORMULA_H
calculateformula.cpp
#include "calculateformula.h"
CalculateFormula::CalculateFormula(CallbackGetSymbolValue symbolHandler, QVariant value)
{
OnGetSymbolValue=symbolHandler;
m_objValue=value;
}
double CalculateFormula::ToDouble(const QString& variable, bool& bOk)
{
return variable.toDouble(&bOk);
}
/// <summary>
/// 判断type1的运算优先级是否大于type2的运算优先级
/// </summary>
/// <param name="type1"></param>
/// <param name="type2"></param>
/// <returns></returns>
bool CalculateFormula::IsHighPriority(int type1,int type2)
{
if (arrPriority[type1][type2]<=0)
{
return true;
}
return false;
}
bool CalculateFormula::ProcessStackData(int type)
{
bool bOk=false;
if (m_stkOperator.count() == 0)
{
m_strErrorMessage = "表达式格式不正确";
return false;
}
if (m_stkData.count() == 0)
{
m_strErrorMessage = "表达式格式不正确";
return false;
}
int realType=m_stkOperator.pop();
double v2=m_stkData.pop();
while(true)
{
if (realType==4&&type==5)
{
break;
}
if (m_stkData.count()==0)
{
m_strErrorMessage="表达式格式不正确";
return false;
}
v2=CalculateValue(m_stkData.pop(),v2,realType,bOk);
if (!bOk)
{
return false;
}
if (m_stkOperator.count()>0)
{
if (type!=5)
{
if (IsHighPriority(m_stkOperator.top(),realType))
{
realType=m_stkOperator.pop();
if (realType==4)
{
m_stkOperator.push(realType);
break;
}
}
else
{
break;
}
}
else
{
realType=m_stkOperator.pop();
}
}
else
{
break;
}
}
m_stkData.push(v2);
if (type!=4&&type!=5)
{
m_stkOperator.push(type);
}
return true;
}
double CalculateFormula::Sqrt(QString param [],bool& bOk)
{
bOk=true;
double ret=0.0;
CalculateFormula cf(OnGetSymbolValue,m_objValue);
if (cf.Calculate(param[0], ret))
{
return sqrt(ret);
}
bOk = false;
m_strErrorMessage = "函数Sqrt有错误" + param[0];
return 0.0;
}
double CalculateFormula::Pow2(QString param [],bool& bOk)
{
bOk=true;
double ret=0.0;
CalculateFormula cf(OnGetSymbolValue, m_objValue);
if (cf.Calculate(param[0], ret))
{
return ret*ret;
}
bOk = false;
m_strErrorMessage = "函数POW2有错误" + param[0];
return 0.0;
}
double CalculateFormula::Sin(QString param [],bool& bOk)
{
bOk = true;
double ret = 0.0;
CalculateFormula cf(OnGetSymbolValue, m_objValue);
if (cf.Calculate(param[0], ret))
{
return sin(ret);
}
bOk = false;
m_strErrorMessage = "函数Sin有错误" + param[0];
return 0.0;
}
double CalculateFormula::Cos(QString param [],bool& bOk)
{
bOk = true;
double ret = 0.0;
CalculateFormula cf(OnGetSymbolValue, m_objValue);
if (cf.Calculate(param[0], ret))
{
return cos(ret);
}
bOk = false;
m_strErrorMessage = "函数Cos有错误" + param[0];
return 0.0;
}
double CalculateFormula::Tan(QString param [],bool& bOk)
{
bOk = true;
double ret = 0.0;
CalculateFormula cf(OnGetSymbolValue, m_objValue);
if (cf.Calculate(param[0], ret))
{
return tan(ret);
}
bOk = false;
m_strErrorMessage = "函数Tan有错误" + param[0];
return 0.0;
}
double CalculateFormula::Exp(QString param [],bool& bOk)
{
bOk = true;
double ret = 0.0;
CalculateFormula cf(OnGetSymbolValue, m_objValue);
if (cf.Calculate(param[0], ret))
{
return exp(ret);
}
bOk = false;
m_strErrorMessage = "函数Exp有错误" + param[0];
return 0.0;
}
double CalculateFormula::Atan(QString param [],bool& bOk)
{
bOk = true;
double ret = 0.0;
CalculateFormula cf(OnGetSymbolValue, m_objValue);
if (cf.Calculate(param[0], ret))
{
return atan(ret);
}
bOk = false;
m_strErrorMessage = "函数Atan[返回角度值]有错误" + param[0];
return 0.0;
}
double CalculateFormula::Atanr(QString param [],bool& bOk)
{
bOk = true;
double ret = 0.0;
CalculateFormula cf(OnGetSymbolValue, m_objValue);
if (cf.Calculate(param[0], ret))
{
return 360 / atan(ret) * MATH_PI;
}
bOk = false;
m_strErrorMessage = "函数Atanr[反回弧度值]有错误" + param[0];
return 0.0;
}
double CalculateFormula::Log(QString param [],bool& bOk)
{
bOk = true;
double ret1 = 0.0;
double ret2 = 0.0;
CalculateFormula cf_1(OnGetSymbolValue, m_objValue);
CalculateFormula cf_2(OnGetSymbolValue, m_objValue);
if (cf_1.Calculate(param[0], ret1) && ret1 !=0 &&
cf_2.Calculate(param[1], ret2))
{
return log(ret1)/log(ret2);
}
bOk = false;
m_strErrorMessage = "函数Log有错误:Log(" + param[0] + "," + param[1] + ")";
return 0.0;
}
double CalculateFormula::Pow(QString param [],bool& bOk)
{
bOk = true;
double ret1 = 0.0;
double ret2 = 0.0;
CalculateFormula cf_1(OnGetSymbolValue, m_objValue);
CalculateFormula cf_2(OnGetSymbolValue, m_objValue);
if (cf_1.Calculate(param[0], ret1) &&
cf_2.Calculate(param[1], ret2))
{
return pow(ret1, ret2);
}
bOk = false;
m_strErrorMessage = "函数Log有错误:Pow(" + param[0] + "," + param[1] + ")";
return 0.0;
}
double CalculateFormula::Abs(QString param [],bool& bOk)
{
bOk = true;
double ret = 0.0;
CalculateFormula cf(OnGetSymbolValue, m_objValue);
if (cf.Calculate(param[0], ret))
{
return fabs(ret);
}
bOk = false;
m_strErrorMessage = "函数Abs有错误" + param[0];
return 0.0;
}
double CalculateFormula::IsNull(QString param [],bool& bOk)
{
bOk = true;
double ret1 = 0.0;
CalculateFormula cf_1(OnGetSymbolValue, m_objValue);
CalculateFormula cf_2(OnGetSymbolValue, m_objValue);
if (cf_1.Calculate(param[0], ret1)) return ret1;
if (cf_2.Calculate(param[1], ret1)) return ret1;
bOk = false;
m_strErrorMessage = "函数IsNull有错误:IsNull(" + param[0] + "," + param[1] + ")";
return 0.0;
}
QString * CalculateFormula::GetParam(const QString& Formula, int& index,int countParam)
{
int indexParam=0;
int countBrace=1;
QString * arrParam=new QString[countParam];
for(int i=0;i<countParam;i++){
arrParam[i]=nullptr;
}
if (Formula[index]!='(')
{
m_strErrorMessage = "表达式格式错误[缺少左括号]";
return nullptr;
}
index++;
while (index<Formula.size())
{
if (Formula[index]=='(')
{
countBrace++;
}
else if (Formula[index]==')')
{
countBrace--;
}
if (countBrace==0)
{
index++;
break;
}
if (Formula[index]==',' && countBrace == 1)
{
indexParam++;
index++;
continue;
}
if (indexParam < countParam)
{
if (Formula[index] != ' ')
{
arrParam[indexParam] += Formula[index];
}
}
index++;
}
if (indexParam<countParam && arrParam[countParam-1] != nullptr)
{
return arrParam;
}
m_strErrorMessage = "表达式参数错误,应为"+QString::number(countParam)+"个参数";
return nullptr;
}
double CalculateFormula::DoFunction(const QString& funName, const QString& Formula, int& index, bool& bOk)
{
double val=0.0;
bOk=true;
QString fun=funName.toLower().trimmed();
if (fun== "exp"){
QString* strParam = GetParam(Formula, index, 1);
if (strParam==nullptr)
{
bOk = false;
} else {
val = Exp(strParam, bOk);
}
delete[] strParam;
} else if (fun== "abs"){
QString* strParam = GetParam(Formula, index, 1);
if (strParam==nullptr)
{
bOk = false;
} else {
val = Abs(strParam, bOk);
}
delete[] strParam;
} else if (fun== "pow"){
QString* strParam = GetParam(Formula, index, 2);
if (strParam==nullptr)
{
bOk = false;
} else {
val = Pow(strParam, bOk);
}
delete[] strParam;
} else if (fun== "isnull"){
QString* strParam = GetParam(Formula, index, 2);
if (strParam==nullptr)
{
bOk = false;
} else {
val = IsNull(strParam, bOk);
}
delete[] strParam;
} else if (fun== "log"){
QString* strParam = GetParam(Formula, index, 2);
if (strParam==nullptr)
{
bOk = false;
} else {
val = Log(strParam, bOk);
}
delete[] strParam;
} else if (fun== "sin"){
QString* strParam = GetParam(Formula, index, 1);
if (strParam==nullptr)
{
bOk = false;
} else {
val = Sin(strParam, bOk);
}
delete[] strParam;
} else if (fun== "cos"){
QString* strParam = GetParam(Formula, index, 1);
if (strParam==nullptr)
{
bOk = false;
} else {
val = Cos(strParam, bOk);
}
delete[] strParam;
} else if (fun== "tan"){
QString* strParam = GetParam(Formula, index, 1);
if (strParam==nullptr)
{
bOk = false;
} else {
val = Tan(strParam, bOk);
}
delete[] strParam;
} else if (fun== "atanr"){
QString* strParam = GetParam(Formula, index, 1);
if (strParam==nullptr)
{
bOk = false;
} else {
val = Atanr(strParam, bOk);
}
delete[] strParam;
} else if (fun== "sqrt"){
QString* strParam = GetParam(Formula, index, 1);
if (strParam==nullptr)
{
bOk = false;
} else {
val = Sqrt(strParam, bOk);
}
delete[] strParam;
} else if (fun== "pow2"){
QString* strParam = GetParam(Formula, index, 1);
if (strParam==nullptr)
{
bOk = false;
} else {
val = Pow2(strParam, bOk);
}
delete[] strParam;
} else {
m_strErrorMessage="不支持的函数"+funName;
bOk=false;
}
return val;
}
double CalculateFormula::CalculateSymbol(const QString& symbol, bool& bOk)
{
bOk=false;
if (OnGetSymbolValue!=nullptr)
{
double ret=OnGetSymbolValue(symbol,m_objValue, bOk);
if (!bOk)
{
m_strErrorMessage="没有定义的变量"+symbol;
return 1.0;
}
return ret;
}
m_strErrorMessage="本程序不能计算变量"+symbol;
return 1.0;
}
bool CalculateFormula::Calculate(const QString& strFormula,double& dResult){
int index=0;
int type=-1;
bool bOk=false;
double dTemp=0.0;
QString strPhrase=GetPhrase(strFormula,index,type);
dResult=0.0;
m_stkData.clear();
m_stkOperator.clear();
while (strPhrase!="")
{
m_strErrorMessage+=strPhrase;
switch(type)
{
case 9:
dTemp=DoFunction(strPhrase,strFormula,index, bOk);
if (!bOk)
{
return false;
}
m_stkData.push(dTemp);
break;
case 7:
dTemp=ToDouble(strPhrase, bOk);
if (!bOk)
{
m_strErrorMessage="表达式输入有误"+strPhrase;
return false;
}
m_stkData.push(dTemp);
break;
case 8:
dTemp=CalculateSymbol(strPhrase, bOk);
if (!bOk)
{
return false;
}
m_stkData.push(dTemp);
break;
default:
if (type>=0&&type<=6)
{
if (m_stkOperator.empty())
{
m_stkOperator.push(type);
}
else
{
if ((type==4||m_stkOperator.top()==4||!IsHighPriority(m_stkOperator.top(),type)) && type!=5)
{
m_stkOperator.push(type);
}
else
{
if (!ProcessStackData(type))
{
return false;
}
}
}
}
else
{
m_strErrorMessage="不支持的运算符"+strPhrase;
return false;
}
break;
}
strPhrase=GetPhrase(strFormula,index,type);
}
if (m_stkData.count()>0)
{
dResult=m_stkData.pop();
}
index=0;
while(!m_stkOperator.empty())
{
if (m_stkData.empty())
{
m_strErrorMessage="表达式不正确";
return false;
}
int tType=m_stkOperator.pop();
if (tType==5)
{
index++;
}
else if (tType==4)
{
index--;
}
dResult=CalculateValue(m_stkData.pop(),dResult,tType,bOk);
if (!bOk)
{
return false;
}
}
return true;
}
double CalculateFormula::CalculateValue(double v1,double v2,int type,bool& bOk)
{
bOk=true;
switch(type)
{
case 0:
return v1+v2;
case 1:
return v1-v2;
case 2:
return v1*v2;
case 3:
if (v2==0)
{
m_strErrorMessage=QObject::tr("除数为零");
bOk=false;
return 0;
}
return v1/v2;
}
m_strErrorMessage=QObject::tr("未知错误:%1").arg(type);
bOk=false;
return 0.0;
}
int CalculateFormula::GetCharType(const char c)
{
switch(c)
{
case '+':
return 0;
case '-':
return 1;
case '*':
return 2;
case '/':
return 3;
case '(':
return 4;
case ')':
return 5;
case '=':
return 6;
default:
if ((c>='0'&&c<='9')||c=='.')
{
return 7;// is number
}
break;
}
return 8;//is char
}
QString CalculateFormula::GetPhrase(const QString& strPhrase,int& newIndex,int& type)
{
QString strTemp="";
int i=newIndex;
int ret=-1;
type=-1;
bool bSecondDispare=false;
if (strPhrase.isEmpty() || strPhrase.size()<=newIndex)
{
return "";
}
ret=GetCharType(strPhrase[i].toLatin1());
if (ret==1||ret==0)
{
if (i==0)
{
do
{
strTemp+=strPhrase[i];
i++;
if (i>=strPhrase.size())
{
break;
}
if ((strPhrase[i]=='E'||strPhrase[i]=='e')&&!bSecondDispare)
{
bSecondDispare=true;
strTemp+='E';
i++;
if (i>=strPhrase.size())
{
break;
}
if (strPhrase[i]=='+'||strPhrase[i]=='-')
{
strTemp+=strPhrase[i];
i++;
if (i>=strPhrase.size())
{
break;
}
}
}
}while(GetCharType(strPhrase[i].toLatin1())==7);
newIndex=i;
type=7;
return strTemp;
}
else if (GetCharType(strPhrase[i-1].toLatin1())>=0&&GetCharType(strPhrase[i-1].toLatin1())<=4)
{
do
{
strTemp+=strPhrase[i];
i++;
if (i>=strPhrase.size())
{
break;
}
if ((strPhrase[i]=='E'||strPhrase[i]=='e')&&!bSecondDispare)
{
bSecondDispare=true;
strTemp+='E';
i++;
if (i>=strPhrase.size())
{
break;
}
if (strPhrase[i]=='+'||strPhrase[i]=='-')
{
strTemp+=strPhrase[i];
i++;
if (i>=strPhrase.size())
{
break;
}
}
}
}while(GetCharType(strPhrase[i].toLatin1())==7);
newIndex=i;
type=7;
return strTemp;
}
else
{
type=ret;
newIndex=i+1;
return strPhrase[i];
}
}
else if (ret>=0&&ret<=6)
{
type=ret;
newIndex=i+1;
return strPhrase[i];
}
else if (ret==7)
{
do
{
strTemp+=strPhrase[i];
i++;
if (i>=strPhrase.size())
{
break;
}
if ((strPhrase[i]=='E'||strPhrase[i]=='e')&&!bSecondDispare)
{
bSecondDispare=true;
strTemp+='E';
i++;
if (i>=strPhrase.size())
{
break;
}
if (strPhrase[i]=='+'||strPhrase[i]=='-')
{
strTemp+=strPhrase[i];
i++;
if (i>=strPhrase.size())
{
break;
}
}
}
}while(GetCharType(strPhrase[i].toLatin1())==7);
newIndex=i;
type=ret;
return strTemp;
}
else if (ret==8)
{
do
{
strTemp+=strPhrase[i];
i++;
if (i>=strPhrase.size())
{
break;
}
}while(GetCharType(strPhrase[i].toLatin1())>=7);
newIndex=i;
if (i<strPhrase.size()&&strPhrase[i]=='(')
{
type=9;
}
else
{
type=ret;
}
return strTemp;
}
return "";
}
使用方法
double s(const QString& symbol, QVariant& v, bool& bOK){
if (symbol=="a"){
bOK=true;
return 1;
}
if (symbol=="b"){
bOK=true;
return 2;
}
bOK=false;
return 0;
}
QVariant vv;//对应变量值获取函数中的参数v
double dRet;
CalculateFormula f(s,vv);
f.Calculate("a+b", dRet);
QMessageBox::information(nullptr,"",QString::number(dRet));