1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef FOUNDATION_ACE_FRAMEWORKS_BASE_UTILS_STRING_EXPRESSION_H
17 #define FOUNDATION_ACE_FRAMEWORKS_BASE_UTILS_STRING_EXPRESSION_H
18
19 #include <functional>
20 #include <map>
21 #include <regex>
22 #include <string>
23 #include <vector>
24
25 namespace OHOS::Ace::StringExpression {
InitMapping(std::map<std::string,int> & mapping)26 void InitMapping(std::map<std::string, int> &mapping)
27 {
28 mapping["+"] = 0;
29 mapping["-"] = 0;
30 mapping["*"] = 1;
31 mapping["/"] = 1;
32 mapping["("] = 2;
33 mapping[")"] = 2;
34 }
35
ConvertDal2Rpn(std::string formula)36 std::vector<std::string> ConvertDal2Rpn(std::string formula)
37 {
38 std::vector<std::string> result;
39 std::vector<std::string> opStack;
40 std::map<std::string, int> OpMapping;
41 std::string curNum, curOp;
42 std::regex calc("calc");
43 std::regex space(" ");
44 std::string ops = "+-*/()";
45 formula = regex_replace(formula, calc, "");
46 formula = regex_replace(formula, space, "");
47 for (std::size_t i = 0; i < formula.size(); ++i) {
48 if (ops.find(formula[i]) == ops.npos) {
49 curNum += formula[i];
50 } else {
51 if (!curNum.empty()) {
52 result.push_back(curNum);
53 curNum.clear();
54 }
55 curOp = formula[i];
56 if (opStack.empty()) {
57 opStack.push_back(curOp);
58 } else if (curOp == "(") {
59 opStack.push_back(curOp);
60 } else if (curOp == ")") {
61 while (opStack.back() != "(") {
62 result.push_back(opStack.back());
63 opStack.pop_back();
64 if (opStack.empty()) {
65 LOGE("ExpressionError, opStack is empty");
66 result.push_back("0");
67 return result;
68 }
69 }
70 opStack.pop_back();
71 } else if (opStack.back() == "(") {
72 opStack.push_back(curOp);
73 } else if (OpMapping[curOp] > OpMapping[opStack.back()] && (!opStack.empty())) {
74 opStack.push_back(curOp);
75 } else {
76 while ((opStack.back() != "(") && (OpMapping[opStack.back()] >= OpMapping[curOp])) {
77 result.push_back(opStack.back());
78 opStack.pop_back();
79 if (opStack.empty())
80 break;
81 }
82 opStack.push_back(curOp);
83 }
84 }
85 }
86 if (!opStack.empty()) {
87 LOGE("opStack is not empty");
88 }
89 return result;
90 }
91
CalculateExp(std::string expression,const std::function<double (const Dimension &)> calcFunc)92 double CalculateExp(std::string expression, const std::function<double(const Dimension&)> calcFunc)
93 {
94 std::vector<std::string> rpnexp = ConvertDal2Rpn(expression);
95 std::vector<double> result;
96 double num = 0.0;
97 std::string ops = "+-*/()";
98 for (std::size_t i = 0; i < rpnexp.size(); ++i) {
99 if (ops.find(rpnexp[i]) == ops.npos) {
100 std::string value = rpnexp[i];
101 Dimension dim = StringUtils::StringToDimensionWithUnit(value);
102 num = calcFunc(dim);
103 result.push_back(num);
104 } else {
105 if (result.size() < 2) {
106 LOGE("ExpressionError, size < 2");
107 return 0.0;
108 }
109 double num1 = result.back();
110 result.pop_back();
111 double num2 = result.back();
112 result.pop_back();
113 double opRes = 0.0;
114 if (rpnexp[i] == "+") {
115 opRes = num2 + num1;
116 } else if (rpnexp[i] == "-") {
117 opRes = num2 - num1;
118 } else if (rpnexp[i] == "*") {
119 opRes = num2 * num1;
120 } else if (rpnexp[i] == "/" && num1 != 0) {
121 opRes = num2 / num1;
122 }
123 result.push_back(opRes);
124 }
125 }
126 if (result.size() == 1) {
127 return result.back();
128 } else {
129 LOGE("ExpressionError");
130 return 0.0;
131 }
132 }
133 } // namespace OHOS::Ace::StringExpression
134
135 #endif // FOUNDATION_ACE_FRAMEWORKS_BASE_UTILS_STRING_EXPRESSION_H