1 /*
2 * Copyright (c) 2023 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 locale governing permissions and
13 * limitations under the License.
14 */
15 #include "rules_engine.h"
16 #include <algorithm>
17 #include "i18n_hilog.h"
18 #include "utils.h"
19
20 namespace OHOS {
21 namespace Global {
22 namespace I18n {
RulesEngine()23 RulesEngine::RulesEngine()
24 {
25 }
26
RulesEngine(DateTimeRule * dateTimeRule,RulesSet & rulesSet)27 RulesEngine::RulesEngine(DateTimeRule* dateTimeRule, RulesSet& rulesSet)
28 {
29 this->dateTimeRule = dateTimeRule;
30 this->rulesMap = rulesSet.rulesMap;
31 this->subRules = rulesSet.subRules;
32 this->param = rulesSet.param;
33 this->paramBackup = rulesSet.paramBackup;
34 Init();
35 }
36
~RulesEngine()37 RulesEngine::~RulesEngine()
38 {
39 }
40
41 // match message based on patterns.
Match(icu::UnicodeString & message)42 std::vector<MatchedDateTimeInfo> RulesEngine::Match(icu::UnicodeString& message)
43 {
44 std::vector<MatchedDateTimeInfo> matches;
45 std::vector<std::string> keys;
46 for (auto& kv : this->patterns) {
47 keys.push_back(kv.first);
48 }
49 std::string res;
50 message.toUTF8String(res);
51 for (auto& key : keys) {
52 UErrorCode status = U_ZERO_ERROR;
53 icu::UnicodeString regex = this->patterns[key];
54 icu::RegexPattern* pattern = icu::RegexPattern::compile(regex,
55 URegexpFlag::UREGEX_CASE_INSENSITIVE, status);
56 if (pattern == nullptr) {
57 HILOG_ERROR_I18N("Match failed because pattern is nullptr.");
58 return matches;
59 }
60 icu::RegexMatcher* matcher = pattern->matcher(message, status);
61 if (matcher == nullptr) {
62 HILOG_ERROR_I18N("Match failed because pattern matcher failed.");
63 delete pattern;
64 return matches;
65 }
66 while (matcher->find(status)) {
67 int begin = matcher->start(status);
68 int end = matcher->end(status);
69 MatchedDateTimeInfo match(begin, end, key);
70 matches.push_back(match);
71 }
72 delete matcher;
73 delete pattern;
74 }
75 return matches;
76 }
77
Init()78 void RulesEngine::Init()
79 {
80 for (const auto& rule : rulesMap) {
81 std::string rulesKey = rule.first;
82 std::string rulesValue = rule.second;
83 rulesValue = InitSubRules(rulesValue);
84 rulesValue = InitOptRules(rulesValue);
85 bool isVaild = InitRules(rulesValue);
86 // replace [param_ ] in the rule with the corresponding regular expression.
87 icu::UnicodeString regex = rulesValue.c_str();
88 if (!regex.trim().isEmpty() && isVaild) {
89 this->patterns.insert({rulesKey, regex});
90 }
91 }
92 }
93
InitRules(std::string & rulesValue)94 bool RulesEngine::InitRules(std::string& rulesValue)
95 {
96 bool isVaild = true;
97 if (this->dateTimeRule == nullptr) {
98 HILOG_ERROR_I18N("InitRules failed because this->dateTimeRule is nullptr.");
99 return false;
100 }
101 icu::RegexPattern* pattern = dateTimeRule->GetPatternsMap()["rules"];
102 if (pattern == nullptr) {
103 HILOG_ERROR_I18N("InitRules failed because pattern is nullptr.");
104 return isVaild;
105 }
106 UErrorCode status = U_ZERO_ERROR;
107 if (param.size() != 0 || paramBackup.size() != 0) {
108 icu::UnicodeString rules = rulesValue.c_str();
109 icu::RegexMatcher* matcher = pattern->matcher(rules, status);
110 if (matcher == nullptr) {
111 HILOG_ERROR_I18N("InitRules failed because pattern matcher failed.");
112 return false;
113 }
114 while (matcher->find(status) && isVaild) {
115 icu::UnicodeString value = matcher->group(1, status);
116 std::string valueStr;
117 value.toUTF8String(valueStr);
118 std::string paramValue = this->dateTimeRule->Get(param, valueStr);
119 std::string paramBackupValue = this->dateTimeRule->Get(paramBackup, valueStr);
120 std::string targetStr =
121 (paramValue.length() == 0 && paramBackupValue.length() != 0) ? paramBackupValue : paramValue;
122 targetStr = (paramValue.length() != 0 && paramBackupValue.length() != 0 &&
123 !DateTimeRule::CompareBeginEnd(paramValue, "]", false) &&
124 !DateTimeRule::CompareBeginEnd(paramValue, "]\\b", false)) ?
125 paramValue + "|" + paramBackupValue : targetStr;
126 isVaild = (targetStr.length() == 0) ? false : true;
127 std::string replaceStr = "[" + valueStr + "]";
128 if (DateTimeRule::trim(paramValue).length() != 0) {
129 rulesValue = StrReplaceAll(rulesValue, replaceStr, targetStr);
130 }
131 }
132 delete matcher;
133 }
134 return isVaild;
135 }
136
137 // replace [paramopt_ ] in the rule with the corresponding regular expression.
InitOptRules(std::string & rule)138 std::string RulesEngine::InitOptRules(std::string& rule)
139 {
140 std::string rulesValue = rule;
141 icu::UnicodeString matchedStr = rule.c_str();
142 UErrorCode status = U_ZERO_ERROR;
143 if (this->dateTimeRule == nullptr) {
144 HILOG_ERROR_I18N("InitOptRules failed because this->dateTimeRule is nullptr.");
145 return rulesValue;
146 }
147 icu::RegexPattern* pattern = dateTimeRule->GetPatternsMap()["optrules"];
148 if (pattern == nullptr) {
149 HILOG_ERROR_I18N("InitOptRules failed because pattern is nullptr.");
150 return rulesValue;
151 }
152 if (param.size() != 0 || paramBackup.size() != 0) {
153 icu::RegexMatcher* matcher = pattern->matcher(matchedStr, status);
154 if (matcher == nullptr) {
155 HILOG_ERROR_I18N("InitOptRules failed because pattern matcher failed.");
156 return rulesValue;
157 }
158 while (matcher->find(status)) {
159 icu::UnicodeString key = matcher->group(1, status);
160 std::string keyStr;
161 key.toUTF8String(keyStr);
162 std::string value = "param_" + keyStr;
163 int begin = matcher->start(status);
164 int end = matcher->end(status);
165 std::string paramValue = this->dateTimeRule->Get(param, value);
166 std::string paramBackupValue = this->dateTimeRule->Get(paramBackup, value);
167 std::string targetStr = paramValue;
168 if (paramValue.length() == 0 && paramBackupValue.length() != 0) {
169 targetStr = paramBackupValue;
170 } else if (DateTimeRule::trim(paramValue).length() != 0 &&
171 DateTimeRule::trim(paramBackupValue).length() != 0) {
172 targetStr = paramValue + '|' + paramBackupValue;
173 }
174 // if there is not corresponding regular expression, delete [paramopt_ ].
175 if (paramValue.length() == 0 && paramBackupValue.length() == 0) {
176 int rIndex = (rule.substr(begin - 1, 1) == "|") ? begin - 1 : begin;
177 std::string replaceStr1 = rule.substr(rIndex, end - rIndex);
178 rulesValue = StrReplaceAll(rulesValue, replaceStr1, "");
179 }
180 std::string replaceStr2 = "[paramopt_" + keyStr + "]";
181 rulesValue = StrReplaceAll(rulesValue, replaceStr2, targetStr);
182 }
183 delete matcher;
184 }
185 return rulesValue;
186 }
187
188 // replace [regex_ ] in the rule with the corresponding regular expression.
InitSubRules(std::string & rule)189 std::string RulesEngine::InitSubRules(std::string& rule)
190 {
191 std::string rulesValue = rule;
192 icu::UnicodeString matchedStr = rule.c_str();
193 UErrorCode status = U_ZERO_ERROR;
194 icu::RegexPattern* pattern = dateTimeRule->GetPatternsMap()["subrules"];
195 if (pattern == nullptr) {
196 HILOG_ERROR_I18N("InitSubRules failed because pattern is nullptr.");
197 return rulesValue;
198 }
199 if (subRules.size() != 0) {
200 icu::RegexMatcher* matcher = pattern->matcher(matchedStr, status);
201 if (matcher == nullptr) {
202 HILOG_ERROR_I18N("InitSubRules failed because pattern matcher failed.");
203 return rulesValue;
204 }
205 while (matcher->find(status)) {
206 icu::UnicodeString text = matcher->group(0, status);
207 icu::UnicodeString value = matcher->group(1, status);
208 std::string valueStr;
209 value.toUTF8String(valueStr);
210 std::string targetStr = subRules[valueStr];
211 std::string replaceStr;
212 text.toUTF8String(replaceStr);
213 rulesValue = StrReplaceAll(rulesValue, replaceStr, targetStr);
214 }
215 delete matcher;
216 }
217 return rulesValue;
218 }
219 } // namespace I18n
220 } // namespace Global
221 } // namespace OHOS