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 #include "base/utils/string_expression.h"
17
18 #include <regex>
19
20 #include "base/log/log.h"
21 #include "base/utils/string_utils.h"
22
23 namespace OHOS::Ace::StringExpression {
InitMapping(std::map<std::string,int> & mapping)24 void InitMapping(std::map<std::string, int>& mapping)
25 {
26 mapping["+"] = 0;
27 mapping["-"] = 0;
28 mapping["*"] = 1;
29 mapping["/"] = 1;
30 mapping["("] = 2;
31 mapping[")"] = 2;
32 }
33
ConvertDal2Rpn(std::string formula)34 std::vector<std::string> ConvertDal2Rpn(std::string formula)
35 {
36 std::vector<std::string> result;
37 std::vector<std::string> opStack;
38 std::map<std::string, int> OpMapping;
39 std::string curNum, curOp;
40 std::regex calc("calc");
41 std::regex space(" ");
42 std::string ops = "+-*/()";
43 formula = regex_replace(formula, calc, "");
44 formula = regex_replace(formula, space, "");
45 for (char i : formula) {
46 if (ops.find(i) == ops.npos) {
47 curNum += i;
48 } else {
49 if (!curNum.empty()) {
50 result.push_back(curNum);
51 curNum.clear();
52 }
53 curOp = i;
54 if (opStack.empty()) {
55 opStack.push_back(curOp);
56 } else if (curOp == "(") {
57 opStack.push_back(curOp);
58 } else if (curOp == ")") {
59 while (opStack.back() != "(") {
60 result.push_back(opStack.back());
61 opStack.pop_back();
62 if (opStack.empty()) {
63 LOGE("ExpressionError, opStack is empty");
64 result.emplace_back("0");
65 return result;
66 }
67 }
68 opStack.pop_back();
69 } else if (opStack.back() == "(") {
70 opStack.push_back(curOp);
71 } else if (OpMapping[curOp] > OpMapping[opStack.back()] && (!opStack.empty())) {
72 opStack.push_back(curOp);
73 } else {
74 while ((opStack.back() != "(") && (OpMapping[opStack.back()] >= OpMapping[curOp])) {
75 result.push_back(opStack.back());
76 opStack.pop_back();
77 if (opStack.empty())
78 break;
79 }
80 opStack.push_back(curOp);
81 }
82 }
83 }
84 if (!opStack.empty()) {
85 LOGE("opStack is not empty");
86 }
87 return result;
88 }
89
CalculateExp(const std::string & expression,const std::function<double (const Dimension &)> & calcFunc)90 double CalculateExp(const std::string& expression, const std::function<double(const Dimension&)>& calcFunc)
91 {
92 std::vector<std::string> rpnexp = ConvertDal2Rpn(expression);
93 std::vector<double> result;
94 double num = 0.0;
95 std::string ops = "+-*/()";
96 for (auto& i : rpnexp) {
97 if (ops.find(i) == ops.npos) {
98 std::string value = i;
99 Dimension dim = StringUtils::StringToDimensionWithUnit(value);
100 num = calcFunc(dim);
101 result.push_back(num);
102 } else {
103 if (result.size() < 2) {
104 LOGE("ExpressionError, size < 2");
105 return 0.0;
106 }
107 double num1 = result.back();
108 result.pop_back();
109 double num2 = result.back();
110 result.pop_back();
111 double opRes = 0.0;
112 if (i == "+") {
113 opRes = num2 + num1;
114 } else if (i == "-") {
115 opRes = num2 - num1;
116 } else if (i == "*") {
117 opRes = num2 * num1;
118 } else if (i == "/" && !NearZero(num1)) {
119 opRes = num2 / num1;
120 }
121 result.push_back(opRes);
122 }
123 }
124 if (result.size() == 1) {
125 return result.back();
126 } else {
127 LOGE("ExpressionError");
128 return 0.0;
129 }
130 }
131 } // namespace OHOS::Ace::StringExpression
132