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