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 "date_time_filter.h"
16 #include <algorithm>
17 #include "hilog/log.h"
18 #include "utils.h"
19
20 namespace OHOS {
21 namespace Global {
22 namespace I18n {
23 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, 0xD001E00, "DateTimeFilter" };
24 using namespace OHOS::HiviewDFX;
25
DateTimeFilter(std::string & locale,DateTimeRule * dateTimeRule)26 DateTimeFilter::DateTimeFilter(std::string& locale, DateTimeRule* dateTimeRule)
27 {
28 this->locale = locale;
29 this->dateTimeRule = dateTimeRule;
30 }
31
~DateTimeFilter()32 DateTimeFilter::~DateTimeFilter()
33 {
34 }
35
36 // type of the time calculated based on the rule number.
GetType(std::string & name)37 int DateTimeFilter::GetType(std::string& name)
38 {
39 int32_t status = 0;
40 int key = ConvertString2Int(name, status);
41 int type;
42 // 19999 and 30000 are the matching rule numbers.
43 if (key > 19999 && key < 30000) {
44 // 20009, 20011 and 21026 are the TYPE_WEEK rule numbers.
45 if (key == 20009 || key == 20011 || key == 21026) {
46 type = FilterType::TYPE_WEEK;
47 // 20010 is the TYPE_TODAY rule numbers.
48 } else if (key == 20010) {
49 type = FilterType::TYPE_TODAY;
50 } else {
51 type = FilterType::TYPE_DATE;
52 }
53 // 29999 - 40000 is the range of the rule number for TYPE_TIME.
54 } else if (key > 29999 && key < 40000) {
55 type = FilterType::TYPE_TIME;
56 // 9999 - 20000 is the range of the rule number for TYPE_DATETIME.
57 } else if (key > 9999 && key < 20000) {
58 type = FilterType::TYPE_DATETIME;
59 } else {
60 type = FilterType::TYPE_TIME_PERIOD;
61 }
62 return type;
63 }
64
Filter(icu::UnicodeString & content,std::vector<MatchedDateTimeInfo> & matches,std::vector<MatchedDateTimeInfo> & clearMatches,std::vector<MatchedDateTimeInfo> & pastMatches)65 std::vector<MatchedDateTimeInfo> DateTimeFilter::Filter(icu::UnicodeString& content,
66 std::vector<MatchedDateTimeInfo>& matches, std::vector<MatchedDateTimeInfo>& clearMatches,
67 std::vector<MatchedDateTimeInfo>& pastMatches)
68 {
69 matches = FilterOverlay(matches);
70 matches = FilterDatePeriod(content, matches);
71 matches = FilterByRules(content, matches, clearMatches);
72 matches = FilterByPast(content, matches, pastMatches);
73 return matches;
74 }
75
FilterOverlay(std::vector<MatchedDateTimeInfo> & matches)76 std::vector<MatchedDateTimeInfo> DateTimeFilter::FilterOverlay(std::vector<MatchedDateTimeInfo>& matches)
77 {
78 if (matches.size() == 0) {
79 return matches;
80 }
81 matches = FilterOverlayFirst(matches);
82 matches = FilterOverlaySecond(matches);
83 std::sort(matches.begin(), matches.end());
84 return matches;
85 }
86
87 // filtering results based on the clear rule.
FilterByRules(icu::UnicodeString & content,std::vector<MatchedDateTimeInfo> & matches,std::vector<MatchedDateTimeInfo> & clears)88 std::vector<MatchedDateTimeInfo> DateTimeFilter::FilterByRules(icu::UnicodeString& content,
89 std::vector<MatchedDateTimeInfo>& matches, std::vector<MatchedDateTimeInfo>& clears)
90 {
91 if (clears.size() == 0) {
92 return matches;
93 }
94 auto matchIterator = matches.begin();
95 while (matchIterator != matches.end()) {
96 MatchedDateTimeInfo match = (*matchIterator);
97 bool isDelete = false;
98 for (auto& clearMatch : clears) {
99 // remove the time within the filter range.
100 if (match.GetBegin() >= clearMatch.GetBegin() && match.GetEnd() <= clearMatch.GetEnd()) {
101 matches.erase(matchIterator);
102 isDelete = true;
103 break;
104 }
105 }
106 if (!isDelete) {
107 matchIterator++;
108 }
109 }
110 return matches;
111 }
112
113 // filtering results based on the past rule.
FilterByPast(icu::UnicodeString & content,std::vector<MatchedDateTimeInfo> & matches,std::vector<MatchedDateTimeInfo> & pasts)114 std::vector<MatchedDateTimeInfo> DateTimeFilter::FilterByPast(icu::UnicodeString& content,
115 std::vector<MatchedDateTimeInfo>& matches, std::vector<MatchedDateTimeInfo>& pasts)
116 {
117 if (pasts.size() == 0) {
118 return matches;
119 }
120 int32_t status = 0;
121 for (auto& pastMatch : pasts) {
122 std::string name = pastMatch.GetRegex();
123 int key = ConvertString2Int(name, status);
124 auto matchIterator = matches.begin();
125 while (matchIterator != matches.end()) {
126 MatchedDateTimeInfo match = (*matchIterator);
127 // fields with number < 200 are placed before the time.
128 if ((key < 200 && pastMatch.GetEnd() == match.GetBegin()) ||
129 // fields with number >= 200 are placed after the time.
130 (key >= 200 && pastMatch.GetBegin() == match.GetEnd())) {
131 matches.erase(matchIterator);
132 break;
133 }
134 matchIterator++;
135 }
136 }
137 return matches;
138 }
139
FilterOverlayFirst(std::vector<MatchedDateTimeInfo> & matches)140 std::vector<MatchedDateTimeInfo> DateTimeFilter::FilterOverlayFirst(std::vector<MatchedDateTimeInfo>& matches)
141 {
142 std::vector<MatchedDateTimeInfo> matchList;
143 for (MatchedDateTimeInfo& match : matches) {
144 bool valid = true;
145 auto matchIterator = matchList.begin();
146 while (matchIterator != matchList.end()) {
147 MatchedDateTimeInfo currentMatch = (*matchIterator);
148 if (!(currentMatch.GetBegin() == match.GetBegin() && currentMatch.GetEnd() == match.GetEnd()) &&
149 !(currentMatch.GetBegin() < match.GetBegin() && match.GetBegin() < currentMatch.GetEnd() &&
150 currentMatch.GetEnd() < match.GetEnd()) && !(match.GetBegin() < currentMatch.GetBegin() &&
151 currentMatch.GetBegin() < match.GetEnd() && match.GetEnd() < currentMatch.GetEnd())) {
152 matchIterator++;
153 continue;
154 }
155 std::string currentRegex = currentMatch.GetRegex();
156 std::string matchRegex = match.GetRegex();
157 if (this->dateTimeRule == nullptr) {
158 HiLog::Error(LABEL, "FilterOverlayFirst failed because this->dateTimeRule is nullptr.");
159 return matchList;
160 }
161 // if the matched time segments overlap, retain the high-priority.
162 if (this->dateTimeRule->CompareLevel(currentRegex, matchRegex) > -1) {
163 valid = false;
164 matchIterator++;
165 } else {
166 matchList.erase(matchIterator);
167 }
168 }
169 if (valid) {
170 matchList.push_back(match);
171 }
172 }
173 return matchList;
174 }
175
FilterOverlaySecond(std::vector<MatchedDateTimeInfo> & matches)176 std::vector<MatchedDateTimeInfo> DateTimeFilter::FilterOverlaySecond(std::vector<MatchedDateTimeInfo>& matches)
177 {
178 std::vector<MatchedDateTimeInfo> matchList;
179 for (MatchedDateTimeInfo& match : matches) {
180 bool valid = true;
181 auto matchIterator = matchList.begin();
182 while (matchIterator != matchList.end()) {
183 MatchedDateTimeInfo currentMatch = (*matchIterator);
184 // if one time within another time, the larger one is retained.
185 if ((currentMatch.GetBegin() > match.GetBegin() && currentMatch.GetEnd() <= match.GetEnd()) ||
186 (currentMatch.GetBegin() == match.GetBegin() && currentMatch.GetEnd() < match.GetEnd())) {
187 matchList.erase(matchIterator);
188 continue;
189 } else if (currentMatch.GetBegin() <= match.GetBegin() && currentMatch.GetEnd() >= match.GetEnd()) {
190 valid = false;
191 matchIterator++;
192 continue;
193 } else {
194 matchIterator++;
195 continue;
196 }
197 }
198 if (valid) {
199 matchList.push_back(match);
200 }
201 }
202 return matchList;
203 }
204
FilterDatePeriod(icu::UnicodeString & content,std::vector<MatchedDateTimeInfo> & matches)205 std::vector<MatchedDateTimeInfo> DateTimeFilter::FilterDatePeriod(icu::UnicodeString& content,
206 std::vector<MatchedDateTimeInfo>& matches)
207 {
208 std::vector<MatchedDateTimeInfo> matchList = matches;
209 matchList = FilterDate(content, matchList);
210 matchList = FilterDateTime(content, matchList);
211 matchList = FilterPeriod(content, matchList);
212 matchList = FilterDateTimePunc(content, matchList);
213 return matchList;
214 }
215
FilterDate(icu::UnicodeString & content,std::vector<MatchedDateTimeInfo> & matches)216 std::vector<MatchedDateTimeInfo> DateTimeFilter::FilterDate(icu::UnicodeString& content,
217 std::vector<MatchedDateTimeInfo>& matches)
218 {
219 std::vector<MatchedDateTimeInfo> result;
220 int lengthMatches = matches.size();
221 for (int i = 0; i < lengthMatches; i++) {
222 MatchedDateTimeInfo match = matches[i];
223 std::string matchRegex = match.GetRegex();
224 int type = GetType(matchRegex);
225 match.SetType(type);
226 if (type != FilterType::TYPE_DATE && type != FilterType::TYPE_TODAY && type != FilterType::TYPE_WEEK) {
227 result.push_back(match);
228 continue;
229 }
230 int hasNum = matches.size() - 1 - i;
231 std::vector<MatchedDateTimeInfo> sub;
232 if (hasNum > 1) {
233 // 1 and 3 indicate the relative positions of the intercepted matches.
234 sub.assign(matches.begin() + i + 1, matches.begin() + i + 3);
235 } else if (hasNum == 1) {
236 // 1 and 2 indicate the relative positions of the intercepted matches.
237 sub.assign(matches.begin() + i + 1, matches.begin() + i + 2);
238 }
239 if (hasNum == 0 || sub.size() == 0) {
240 match.SetType(FilterType::TYPE_DATE);
241 result.push_back(match);
242 continue;
243 }
244 int status = NestDealDate(content, match, sub, -1);
245 match.SetType(FilterType::TYPE_DATE);
246 if (status == DateCombine::NOT_COMBINE) {
247 result.push_back(match);
248 continue;
249 } else if (status == DateCombine::TWO_COMBINE) {
250 i++;
251 } else {
252 // 2 indicates that the subsequent two time points and the current time point can be combined.
253 i = i + 2;
254 }
255 DealMatchE(content, matches[i], match);
256 result.push_back(match);
257 }
258 return result;
259 }
260
261 // process time that can be merged
DealMatchE(icu::UnicodeString & content,MatchedDateTimeInfo & nextMatch,MatchedDateTimeInfo & match)262 void DateTimeFilter::DealMatchE(icu::UnicodeString& content, MatchedDateTimeInfo& nextMatch,
263 MatchedDateTimeInfo& match)
264 {
265 int add = 0;
266 int leftIndex = content.indexOf('(', match.GetEnd());
267 if (leftIndex != -1 && leftIndex < nextMatch.GetBegin()) {
268 int end = content.indexOf(')', nextMatch.GetEnd());
269 if (end != -1) {
270 icu::UnicodeString right = content.tempSubString(nextMatch.GetEnd(), end + 1 - nextMatch.GetEnd());
271 if (right.trim() == ')') {
272 add = end - nextMatch.GetEnd() + 1;
273 }
274 }
275 }
276 match.SetEnd(nextMatch.GetEnd() + add);
277 }
278
279 // process two times connected with keywords
FilterDateTime(icu::UnicodeString & content,std::vector<MatchedDateTimeInfo> & matches)280 std::vector<MatchedDateTimeInfo> DateTimeFilter::FilterDateTime(icu::UnicodeString& content,
281 std::vector<MatchedDateTimeInfo>& matches)
282 {
283 if (matches.size() == 0) {
284 return matches;
285 }
286 UErrorCode status = U_ZERO_ERROR;
287 icu::RegexPattern* pattern = dateTimeRule->GetPatternsMap()["datetime"];
288 if (pattern == nullptr) {
289 HiLog::Error(LABEL, "FilterDateTime failed because pattern is nullptr.");
290 return matches;
291 }
292 std::string::size_type matchIndex = 1;
293 std::string::size_type lastMatchIndex = 0;
294 while (matchIndex < matches.size()) {
295 bool isDelete = false;
296 MatchedDateTimeInfo match = matches[matchIndex];
297 MatchedDateTimeInfo lastMatch = matches[lastMatchIndex];
298 int lType = lastMatch.GetType();
299 int cType = match.GetType();
300 if ((lType == FilterType::TYPE_DATE && cType == FilterType::TYPE_TIME) ||
301 (lType == FilterType::TYPE_DATE && cType == FilterType::TYPE_TIME_PERIOD && match.IsTimePeriod()) ||
302 (lType == FilterType::TYPE_TIME && cType == FilterType::TYPE_DATE) ||
303 (lType == FilterType::TYPE_TIME_PERIOD && lastMatch.IsTimePeriod() && cType == FilterType::TYPE_DATE)) {
304 // truncate the substring between two times.
305 icu::UnicodeString joiner = content.tempSubString(lastMatch.GetEnd(),
306 match.GetBegin() - lastMatch.GetEnd());
307 icu::RegexMatcher* matcher = pattern->matcher(joiner, status);
308 bool isJoiner = (joiner.trim().isEmpty()) ? true : matcher->matches(status);
309 // the substring meets the rule, the two times are combined.
310 if (isJoiner) {
311 matches[lastMatchIndex].SetEnd(match.GetEnd());
312 int lastType = ((lType == FilterType::TYPE_DATE && cType == FilterType::TYPE_TIME) ||
313 (lType == FilterType::TYPE_TIME && cType == FilterType::TYPE_DATE)) ?
314 FilterType::TYPE_DATETIME : FilterType::TYPE_TIME_PERIOD;
315 matches[lastMatchIndex].SetType(lastType);
316 matches.erase(matches.begin() + matchIndex);
317 isDelete = true;
318 } else {
319 isDelete = DealBrackets(content, matches, matchIndex, matches[lastMatchIndex], match);
320 }
321 delete matcher;
322 }
323 if (!isDelete) {
324 lastMatchIndex = matchIndex;
325 matchIndex++;
326 }
327 }
328 return matches;
329 }
330
331 // process the time period consisting of two times.
FilterPeriod(icu::UnicodeString & content,std::vector<MatchedDateTimeInfo> & matches)332 std::vector<MatchedDateTimeInfo> DateTimeFilter::FilterPeriod(icu::UnicodeString& content,
333 std::vector<MatchedDateTimeInfo>& matches)
334 {
335 if (matches.size() == 0) {
336 return matches;
337 }
338 UErrorCode status = U_ZERO_ERROR;
339 icu::RegexPattern* pattern = dateTimeRule->GetPatternsMap()["period"];
340 if (pattern == nullptr) {
341 HiLog::Error(LABEL, "FilterPeriod failed because pattern is nullptr.");
342 return matches;
343 }
344 std::string::size_type matchIndex = 1;
345 std::string::size_type currentMatchIndex = 0;
346 while (matchIndex < matches.size()) {
347 MatchedDateTimeInfo match = matches[matchIndex];
348 MatchedDateTimeInfo currentMatch = matches[currentMatchIndex];
349 int cType = currentMatch.GetType();
350 int nType = match.GetType();
351 if ((cType == nType && (cType == FilterType::TYPE_DATE || cType == FilterType::TYPE_TIME ||
352 cType == FilterType::TYPE_DATETIME)) || (cType == FilterType::TYPE_DATETIME &&
353 nType == FilterType::TYPE_TIME)) {
354 icu::UnicodeString matchContent = content.tempSubString(currentMatch.GetEnd(),
355 match.GetBegin() - currentMatch.GetEnd());
356 icu::RegexMatcher* matcher = pattern->matcher(matchContent, status);
357 if (matcher == nullptr) {
358 HiLog::Error(LABEL, "FilterPeriod failed because pattern matcher failed.");
359 return matches;
360 }
361 if (matcher->matches(status)) {
362 matches[currentMatchIndex].SetEnd(match.GetEnd());
363 matches[currentMatchIndex].SetType(FilterType::TYPE_TIME_PERIOD);
364 bool isTimePeriod = (cType == FilterType::TYPE_TIME)? true : false;
365 matches[currentMatchIndex].SetIsTimePeriod(isTimePeriod);
366 matches.erase(matches.begin() + matchIndex);
367 } else {
368 currentMatchIndex = matchIndex;
369 matchIndex++;
370 }
371 delete matcher;
372 } else {
373 currentMatchIndex = matchIndex;
374 matchIndex++;
375 }
376 }
377 return matches;
378 }
379
380 // process the time separated by punctuation
FilterDateTimePunc(icu::UnicodeString & content,std::vector<MatchedDateTimeInfo> & matches)381 std::vector<MatchedDateTimeInfo> DateTimeFilter::FilterDateTimePunc(icu::UnicodeString& content,
382 std::vector<MatchedDateTimeInfo>& matches)
383 {
384 if (matches.size() == 0) {
385 return matches;
386 }
387 std::string::size_type matchIndex = 1;
388 std::string::size_type currentMatchIndex = 0;
389 while (matchIndex < matches.size()) {
390 MatchedDateTimeInfo match = matches[matchIndex];
391 MatchedDateTimeInfo currentMatch = matches[currentMatchIndex];
392 int cType = currentMatch.GetType();
393 int lType = match.GetType();
394 if ((cType == FilterType::TYPE_DATE && lType == FilterType::TYPE_TIME) ||
395 (cType == FilterType::TYPE_DATE && lType == FilterType::TYPE_TIME_PERIOD && match.IsTimePeriod()) ||
396 (cType == FilterType::TYPE_TIME && lType == FilterType::TYPE_DATE) ||
397 (cType == FilterType::TYPE_TIME_PERIOD && currentMatch.IsTimePeriod() && lType == FilterType::TYPE_DATE)) {
398 bool isPunc = false;
399 icu::UnicodeString ss = content.tempSubString(currentMatch.GetEnd(),
400 match.GetBegin() - currentMatch.GetEnd());
401 if (ss.trim() == ',' || ss.trim() == ",") {
402 isPunc = true;
403 }
404 if (isPunc) {
405 matches[currentMatchIndex].SetEnd(match.GetEnd());
406 int currentType = ((cType == FilterType::TYPE_DATE && lType == FilterType::TYPE_TIME) ||
407 cType == FilterType::TYPE_TIME) ? FilterType::TYPE_DATETIME : FilterType::TYPE_TIME_PERIOD;
408 matches[currentMatchIndex].SetType(currentType);
409 matches.erase(matches.begin() + matchIndex);
410 } else {
411 currentMatchIndex = matchIndex;
412 matchIndex++;
413 }
414 } else {
415 currentMatchIndex = matchIndex;
416 matchIndex++;
417 }
418 }
419 return matches;
420 }
421
DealBrackets(icu::UnicodeString & content,std::vector<MatchedDateTimeInfo> & matches,int matchIndex,MatchedDateTimeInfo & lastMatch,MatchedDateTimeInfo & currentMatch)422 bool DateTimeFilter::DealBrackets(icu::UnicodeString& content, std::vector<MatchedDateTimeInfo>& matches,
423 int matchIndex, MatchedDateTimeInfo& lastMatch, MatchedDateTimeInfo& currentMatch)
424 {
425 int lType = lastMatch.GetType();
426 int cType = currentMatch.GetType();
427 if (lType == FilterType::TYPE_TIME) {
428 int add = 0;
429 icu::UnicodeString endStr = content.tempSubString(lastMatch.GetEnd());
430 UErrorCode status = U_ZERO_ERROR;
431 icu::RegexPattern* pattern = dateTimeRule->GetPatternsMap()["brackets"];
432 if (pattern == nullptr) {
433 HiLog::Error(LABEL, "DealBrackets failed because pattern is nullptr.");
434 return false;
435 }
436 icu::RegexMatcher* matcher = pattern->matcher(endStr, status);
437 if (matcher == nullptr) {
438 HiLog::Error(LABEL, "DealBrackets failed because pattern matcher failed.");
439 return false;
440 }
441 icu::UnicodeString groupStr;
442 if (matcher->find(status)) {
443 groupStr = matcher->group(1, status);
444 add = matcher->group(status).length();
445 }
446 delete matcher;
447 if (!groupStr.isEmpty() && groupStr.trim() == content.tempSubString(currentMatch.GetBegin(),
448 currentMatch.GetEnd() - currentMatch.GetBegin()).trim()) {
449 lastMatch.SetEnd(lastMatch.GetEnd() + add);
450 lastMatch.SetType(FilterType::TYPE_DATETIME);
451 matches.erase(matches.begin() + matchIndex);
452 return true;
453 }
454 } else if (lType == FilterType::TYPE_DATE && cType == FilterType::TYPE_TIME) {
455 icu::UnicodeString beginStr = content.tempSubString(0, lastMatch.GetBegin());
456 icu::UnicodeString endStr = content.tempSubString(lastMatch.GetEnd(),
457 currentMatch.GetBegin() - lastMatch.GetEnd());
458 if (beginStr.trim().endsWith('(') && endStr.trim() == ')') {
459 int bracketLastIndex = beginStr.lastIndexOf('(');
460 lastMatch.SetBegin(bracketLastIndex);
461 lastMatch.SetEnd(currentMatch.GetEnd());
462 lastMatch.SetType(FilterType::TYPE_DATETIME);
463 matches.erase(matches.begin() + matchIndex);
464 return true;
465 }
466 }
467 return false;
468 }
469
NestDealDate(icu::UnicodeString & content,MatchedDateTimeInfo & current,std::vector<MatchedDateTimeInfo> & matches,int preType)470 int DateTimeFilter::NestDealDate(icu::UnicodeString& content, MatchedDateTimeInfo& current,
471 std::vector<MatchedDateTimeInfo>& matches, int preType)
472 {
473 int result = 0;
474 MatchedDateTimeInfo nextMatch = matches[0];
475 std::string nextRegex = nextMatch.GetRegex();
476 int nextType = GetType(nextRegex);
477 if (nextType != FilterType::TYPE_DATE && nextType != FilterType::TYPE_TODAY && nextType != FilterType::TYPE_WEEK) {
478 return result;
479 }
480 std::string currentRegex = current.GetRegex();
481 if (nextType == GetType(currentRegex) || nextType == preType) {
482 return result;
483 }
484 result = GetResult(content, current, nextMatch, matches);
485 return result;
486 }
487
GetResult(icu::UnicodeString & content,MatchedDateTimeInfo & current,MatchedDateTimeInfo & nextMatch,std::vector<MatchedDateTimeInfo> & matches)488 int DateTimeFilter::GetResult(icu::UnicodeString& content, MatchedDateTimeInfo& current,
489 MatchedDateTimeInfo& nextMatch, std::vector<MatchedDateTimeInfo>& matches)
490 {
491 int result = 0;
492 icu::UnicodeString ss = content.tempSubString(current.GetEnd(), nextMatch.GetBegin() - current.GetEnd());
493 if (this->dateTimeRule == nullptr) {
494 HiLog::Error(LABEL, "GetResult failed because this->dateTimeRule is nullptr.");
495 return result;
496 }
497 if (this->dateTimeRule->IsRelDates(ss, this->locale) || ss.trim() == '(') {
498 bool isThree = false;
499 if (matches.size() > 1) {
500 std::vector<MatchedDateTimeInfo> nextMatches(matches.begin() + 1, matches.end());
501 int connect = NestDealDate(content, nextMatch, nextMatches, current.GetType());
502 if (connect == DateCombine::TWO_COMBINE) {
503 isThree = true;
504 }
505 }
506 bool isBrackets = false;
507 if (ss.trim() == '(') {
508 icu::UnicodeString endStr = content.tempSubString(current.GetEnd());
509 UErrorCode status = U_ZERO_ERROR;
510 icu::RegexPattern* pattern = dateTimeRule->GetPatternsMap()["brackets"];
511 if (pattern == nullptr) {
512 HiLog::Error(LABEL, "GetResult failed because pattern is nullptr.");
513 return result;
514 }
515 icu::RegexMatcher* matcher = pattern->matcher(endStr, status);
516 if (matcher == nullptr) {
517 HiLog::Error(LABEL, "GetResult failed because pattern matcher failed.");
518 return result;
519 }
520 icu::UnicodeString str = matcher->find(status) ? matcher->group(1, status) : "";
521 int end = isThree ? matches[1].GetEnd() : nextMatch.GetEnd();
522 if (!str.isEmpty() && str.trim() == content.tempSubString(nextMatch.GetBegin(),
523 end - nextMatch.GetBegin()).trim()) {
524 isBrackets = true;
525 }
526 delete matcher;
527 }
528 if (this->dateTimeRule->IsRelDates(ss, this->locale) || isBrackets) {
529 result = isThree ? DateCombine::ALL_COMBINE : DateCombine::TWO_COMBINE;
530 }
531 }
532 return result;
533 }
534 } // namespace I18n
535 } // namespace Global
536 } // namespace OHOS