• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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