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 language governing permissions and
13 * limitations under the License.
14 */
15 #include "positive_rule.h"
16 #include "i18n_hilog.h"
17 #include "phonenumbers/phonenumberutil.h"
18 #include "phonenumbers/phonenumber.h"
19 #include "phonenumbers/shortnumberinfo.h"
20
21 namespace OHOS {
22 namespace Global {
23 namespace I18n {
24 using i18n::phonenumbers::PhoneNumber;
25 using i18n::phonenumbers::PhoneNumberUtil;
26 using i18n::phonenumbers::ShortNumberInfo;
PositiveRule(icu::UnicodeString & regex,std::string & handleType,std::string & insensitive)27 PositiveRule::PositiveRule(icu::UnicodeString& regex, std::string& handleType, std::string& insensitive)
28 {
29 this->regex = regex;
30 this->handleType = handleType;
31 this->insensitive = insensitive;
32 }
33
GetPattern()34 icu::RegexPattern* PositiveRule::GetPattern()
35 {
36 UErrorCode status = U_ZERO_ERROR;
37 icu::RegexPattern* pattern;
38 // Sets whether regular expression matching is case sensitive
39 if (insensitive == "True") {
40 pattern = icu::RegexPattern::compile(this->regex, URegexpFlag::UREGEX_CASE_INSENSITIVE, status);
41 } else {
42 pattern = icu::RegexPattern::compile(this->regex, 0, status);
43 }
44 if (U_FAILURE(status)) {
45 HILOG_ERROR_I18N("PositiveRule::GetPattern: Compile regex pattern failed.");
46 return nullptr;
47 }
48 return pattern;
49 }
50
51 // check whether the bracket at the start position are redundant
IsNumberWithOneBracket(icu::UnicodeString & message)52 bool PositiveRule::IsNumberWithOneBracket(icu::UnicodeString& message)
53 {
54 if (message.isEmpty()) {
55 return false;
56 }
57 int numLeft = 0;
58 int numRight = 0;
59 int len = message.length();
60 for (int i = 0; i < len; i++) {
61 if (message[i] == '(' || message[i] == '[') {
62 numLeft++;
63 }
64 if (message[i] == ')' || message[i] == ']') {
65 numRight++;
66 }
67 }
68 if (numLeft > numRight && (message[0] == '(' || message[0] == '[')) {
69 return true;
70 }
71 return false;
72 }
73
DealStringWithOneBracket(icu::UnicodeString & message)74 icu::UnicodeString PositiveRule::DealStringWithOneBracket(icu::UnicodeString& message)
75 {
76 if (IsNumberWithOneBracket(message)) {
77 return message.tempSubString(1);
78 }
79 return message;
80 }
81
Handle(PhoneNumberMatch * match,icu::UnicodeString & message)82 std::vector<MatchedNumberInfo> PositiveRule::Handle(PhoneNumberMatch* match, icu::UnicodeString& message)
83 {
84 if (match == nullptr) {
85 return {};
86 }
87 icu::UnicodeString rawString = match->raw_string().c_str();
88 icu::UnicodeString str = DealStringWithOneBracket(rawString);
89 icu::RegexPattern* pattern = this->GetPattern();
90 if (pattern == nullptr) {
91 return {};
92 }
93 UErrorCode status = U_ZERO_ERROR;
94 icu::RegexMatcher* mat1 = pattern->matcher(str, status);
95 if (mat1 != nullptr && mat1->find(status)) {
96 std::vector<MatchedNumberInfo> infoList = this->HandleInner(match, message);
97 delete mat1;
98 delete pattern;
99 return infoList;
100 }
101 delete mat1;
102 icu::RegexMatcher* mat2 = pattern->matcher(message, status);
103 if (mat2 != nullptr && mat2->find(status)) {
104 std::vector<MatchedNumberInfo> infoList = this->HandleInner(match, message);
105 delete mat2;
106 delete pattern;
107 return infoList;
108 }
109 delete mat2;
110 delete pattern;
111 return {};
112 }
113
HandleInner(PhoneNumberMatch * possibleNumber,icu::UnicodeString & message)114 std::vector<MatchedNumberInfo> PositiveRule::HandleInner(PhoneNumberMatch *possibleNumber, icu::UnicodeString& message)
115 {
116 if (handleType == "Operator") {
117 return HandleOperator(possibleNumber, message);
118 } else if (handleType == "Blank") {
119 return HandleBlank(possibleNumber, message);
120 } else if (handleType == "Slant") {
121 return HandleSlant(possibleNumber, message);
122 } else if (handleType == "StartWithMobile") {
123 return HandleStartWithMobile(possibleNumber, message);
124 } else if (handleType == "EndWithMobile") {
125 return HandleEndWithMobile(possibleNumber, message);
126 }
127 return HandleDefault(possibleNumber, message);
128 }
129
HandleDefault(PhoneNumberMatch * possibleNumber,icu::UnicodeString & message)130 std::vector<MatchedNumberInfo> PositiveRule::HandleDefault(PhoneNumberMatch* possibleNumber,
131 icu::UnicodeString& message)
132 {
133 MatchedNumberInfo matcher;
134 matcher.SetBegin(0);
135 matcher.SetEnd(1);
136 icu::UnicodeString content = "";
137 matcher.SetContent(content);
138 std::vector<MatchedNumberInfo> matchedNumberInfoList;
139 matchedNumberInfoList.push_back(matcher);
140 return matchedNumberInfoList;
141 }
142
HandleOperator(PhoneNumberMatch * possibleNumber,icu::UnicodeString & message)143 std::vector<MatchedNumberInfo> PositiveRule::HandleOperator(PhoneNumberMatch* possibleNumber,
144 icu::UnicodeString& message)
145 {
146 std::vector<MatchedNumberInfo> matchedNumberInfoList;
147 if (possibleNumber == nullptr) {
148 return matchedNumberInfoList;
149 }
150 MatchedNumberInfo matcher;
151 if (possibleNumber->raw_string()[0] == '(' || possibleNumber->raw_string()[0] == '[') {
152 matcher.SetBegin(possibleNumber->start() + 1);
153 } else {
154 matcher.SetBegin(possibleNumber->start());
155 }
156 matcher.SetEnd(possibleNumber->end());
157 matcher.SetContent(message);
158 matchedNumberInfoList.push_back(matcher);
159 return matchedNumberInfoList;
160 }
161
HandleBlank(PhoneNumberMatch * possibleNumber,icu::UnicodeString & message)162 std::vector<MatchedNumberInfo> PositiveRule::HandleBlank(PhoneNumberMatch* possibleNumber, icu::UnicodeString& message)
163 {
164 std::vector<MatchedNumberInfo> matchedNumberInfoList;
165 if (possibleNumber == nullptr) {
166 return matchedNumberInfoList;
167 }
168 icu::RegexPattern* pattern = GetPattern();
169 if (pattern == nullptr) {
170 return matchedNumberInfoList;
171 }
172 UErrorCode status = U_ZERO_ERROR;
173 icu::UnicodeString number = possibleNumber->raw_string().c_str();
174 icu::RegexMatcher* matcher = pattern->matcher(number, status);
175 if (U_FAILURE(status) || matcher == nullptr) {
176 HILOG_ERROR_I18N("PositiveRule::HandleBlank: Pattern match failed.");
177 return {};
178 }
179 // exclude phone number 2333333
180 icu::UnicodeString negativeRegex = "(?<![-\\d])(23{6,7})(?![-\\d])";
181 icu::RegexMatcher negativePattern(negativeRegex, 0, status);
182 if (U_FAILURE(status)) {
183 HILOG_ERROR_I18N("PositiveRule::HandleBlank: Create negative pattern failed.");
184 return {};
185 }
186 // exclude phone number 5201314
187 icu::UnicodeString speString = "5201314";
188 negativePattern.reset(number);
189 if (matcher->find()) {
190 if (negativePattern.find() || number == speString) {
191 delete matcher;
192 delete pattern;
193 return matchedNumberInfoList;
194 }
195 MatchedNumberInfo matchedNumberInfo;
196 if (possibleNumber->raw_string()[0] != '(' && possibleNumber->raw_string()[0] != '[') {
197 matchedNumberInfo.SetBegin(matcher->start(status) + possibleNumber->start());
198 } else {
199 matchedNumberInfo.SetBegin(possibleNumber->start());
200 }
201 matchedNumberInfo.SetEnd(matcher->end(status) + possibleNumber->start());
202 matchedNumberInfo.SetContent(number);
203 matchedNumberInfoList.push_back(matchedNumberInfo);
204 }
205 delete matcher;
206 delete pattern;
207 return matchedNumberInfoList;
208 }
209
HandleSlant(PhoneNumberMatch * possibleNumber,icu::UnicodeString & message)210 std::vector<MatchedNumberInfo> PositiveRule::HandleSlant(PhoneNumberMatch* possibleNumber, icu::UnicodeString& message)
211 {
212 std::vector<MatchedNumberInfo> matchedNumberInfoList;
213 if (possibleNumber == nullptr) {
214 return matchedNumberInfoList;
215 }
216 icu::RegexPattern* pattern = GetPattern();
217 if (pattern == nullptr) {
218 return matchedNumberInfoList;
219 }
220 UErrorCode status = U_ZERO_ERROR;
221 icu::UnicodeString number = possibleNumber->raw_string().c_str();
222 icu::RegexMatcher* matcher = pattern->matcher(number, status);
223 if (U_FAILURE(status) || matcher == nullptr) {
224 HILOG_ERROR_I18N("PositiveRule::HandleSlant: Pattern match failed.");
225 return matchedNumberInfoList;
226 }
227 if (matcher->find()) {
228 int start = matcher->start(status);
229 std::vector<MatchedNumberInfo> tempList = GetNumbersWithSlant(number);
230 // 2 is the size of tempList.
231 if (tempList.size() == 2 && start == 1) {
232 start = 0;
233 }
234 if (tempList.size() > 0) {
235 MatchedNumberInfo matchedNumberInfo;
236 matchedNumberInfo.SetBegin(tempList[0].GetBegin() + start + possibleNumber->start());
237 matchedNumberInfo.SetEnd(tempList[0].GetEnd() + possibleNumber->start());
238 icu::UnicodeString contentFirst = tempList[0].GetContent();
239 matchedNumberInfo.SetContent(contentFirst);
240 matchedNumberInfoList.push_back(matchedNumberInfo);
241 // 2 is the size of tempList.
242 if (tempList.size() == 2) {
243 MatchedNumberInfo numberInfo;
244 numberInfo.SetBegin(tempList[1].GetBegin() + start + possibleNumber->start());
245 numberInfo.SetEnd(tempList[1].GetEnd() + possibleNumber->start());
246 icu::UnicodeString contentSecond = tempList[1].GetContent();
247 numberInfo.SetContent(contentSecond);
248 matchedNumberInfoList.push_back(numberInfo);
249 }
250 }
251 }
252 delete matcher;
253 delete pattern;
254 return matchedNumberInfoList;
255 }
256
HandleStartWithMobile(PhoneNumberMatch * possibleNumber,icu::UnicodeString & message)257 std::vector<MatchedNumberInfo> PositiveRule::HandleStartWithMobile(PhoneNumberMatch* possibleNumber,
258 icu::UnicodeString& message)
259 {
260 return HandlePossibleNumberWithPattern(possibleNumber, message, false);
261 }
262
HandleEndWithMobile(PhoneNumberMatch * possibleNumber,icu::UnicodeString & message)263 std::vector<MatchedNumberInfo> PositiveRule::HandleEndWithMobile(PhoneNumberMatch* possibleNumber,
264 icu::UnicodeString& message)
265 {
266 return HandlePossibleNumberWithPattern(possibleNumber, message, true);
267 }
268
269 // identify short number separated by '/'
GetNumbersWithSlant(icu::UnicodeString & testStr)270 std::vector<MatchedNumberInfo> PositiveRule::GetNumbersWithSlant(icu::UnicodeString& testStr)
271 {
272 std::vector<MatchedNumberInfo> shortList;
273 ShortNumberInfo* shortInfo = new (std::nothrow) ShortNumberInfo();
274 if (shortInfo == nullptr) {
275 HILOG_ERROR_I18N("ShortNumberInfo construct failed.");
276 return shortList;
277 }
278 std::string numberFisrt = "";
279 std::string numberEnd = "";
280 int slantIndex = 0;
281 for (int i = 0; i < testStr.length(); i++) {
282 if (testStr[i] == '/' || testStr[i] == '|') {
283 slantIndex = i;
284 testStr.tempSubString(0, i).toUTF8String(numberFisrt);
285 testStr.tempSubString(i + 1).toUTF8String(numberEnd);
286 }
287 }
288 PhoneNumber phoneNumberFirst;
289 PhoneNumber phoneNumberEnd;
290 PhoneNumberUtil* pnu = PhoneNumberUtil::GetInstance();
291 if (pnu == nullptr) {
292 delete shortInfo;
293 HILOG_ERROR_I18N("PositiveRule::GetNumbersWithSlant: Get phone number util failed.");
294 return shortList;
295 }
296 pnu->Parse(numberFisrt, "CN", &phoneNumberFirst);
297 pnu->Parse(numberEnd, "CN", &phoneNumberEnd);
298 if (shortInfo->IsValidShortNumber(phoneNumberFirst)) {
299 MatchedNumberInfo matchedNumberInfoFirst;
300 matchedNumberInfoFirst.SetBegin(0);
301 matchedNumberInfoFirst.SetEnd(slantIndex);
302 icu::UnicodeString contentFirst = numberFisrt.c_str();
303 matchedNumberInfoFirst.SetContent(contentFirst);
304 shortList.push_back(matchedNumberInfoFirst);
305 }
306 if (shortInfo->IsValidShortNumber(phoneNumberEnd)) {
307 MatchedNumberInfo matchedNumberInfoEnd;
308 matchedNumberInfoEnd.SetBegin(slantIndex + 1);
309 matchedNumberInfoEnd.SetEnd(testStr.length());
310 icu::UnicodeString contentEnd = numberEnd.c_str();
311 matchedNumberInfoEnd.SetContent(contentEnd);
312 shortList.push_back(matchedNumberInfoEnd);
313 }
314 delete shortInfo;
315 return shortList;
316 }
317
HandlePossibleNumberWithPattern(PhoneNumberMatch * possibleNumber,icu::UnicodeString & message,bool isStartsWithNumber)318 std::vector<MatchedNumberInfo> PositiveRule::HandlePossibleNumberWithPattern(PhoneNumberMatch* possibleNumber,
319 icu::UnicodeString& message, bool isStartsWithNumber)
320 {
321 std::vector<MatchedNumberInfo> matchedList;
322 if (possibleNumber == nullptr) {
323 return matchedList;
324 }
325 icu::RegexPattern* pattern = GetPattern();
326 if (pattern == nullptr) {
327 HILOG_ERROR_I18N("PositiveRule::HandlePossibleNumberWithPattern: RegexPattern is nullptr.");
328 return matchedList;
329 }
330 UErrorCode status = U_ZERO_ERROR;
331 icu::RegexMatcher* mat = pattern->matcher(message, status);
332 if (U_FAILURE(status) || mat == nullptr) {
333 HILOG_ERROR_I18N("PositiveRule::HandlePossibleNumberWithPattern: Pattern match failed.");
334 return matchedList;
335 }
336 icu::UnicodeString possible = possibleNumber->raw_string().c_str();
337 while (mat->find(status)) {
338 int start = mat->start(status);
339 int end = mat->end(status);
340 icu::UnicodeString matched = message.tempSubString(start, end - start);
341 bool isMatch = isStartsWithNumber ? matched.startsWith(possible) : matched.endsWith(possible);
342 if (isMatch) {
343 MatchedNumberInfo info;
344 info.SetBegin(isStartsWithNumber ? start : end - possible.length());
345 info.SetEnd(isStartsWithNumber ? (start + possible.length()) : end);
346 info.SetContent(possible);
347 matchedList.push_back(info);
348 }
349 }
350 delete mat;
351 delete pattern;
352 return matchedList;
353 }
354 } // namespace I18n
355 } // namespace Global
356 } // namespace OHOS