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