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