1 /*
2 * Copyright (c) 2021-2022 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
16 #ifndef FOUNDATION_ACE_FRAMEWORKS_BASE_UTILS_STRING_UTILS_H
17 #define FOUNDATION_ACE_FRAMEWORKS_BASE_UTILS_STRING_UTILS_H
18
19 #include <climits>
20 #include <cmath>
21 #include <codecvt>
22 #include <cstring>
23 #include <locale>
24 #include <sstream>
25 #include <string>
26 #include <vector>
27
28 #include "base/geometry/calc_dimension.h"
29 #include "base/geometry/dimension.h"
30 #include "base/utils/linear_map.h"
31 #include "base/utils/utils.h"
32
33 namespace OHOS::Ace::StringUtils {
34
35 ACE_FORCE_EXPORT extern const char DEFAULT_STRING[];
36 ACE_EXPORT extern const std::wstring DEFAULT_WSTRING;
37 ACE_FORCE_EXPORT extern const std::u16string DEFAULT_USTRING;
38 ACE_EXPORT extern const std::u32string DEFAULT_U32STRING;
39 constexpr int32_t TEXT_CASE_LOWERCASE = 1;
40 constexpr int32_t TEXT_CASE_UPPERCASE = 2;
41 constexpr double PERCENT_VALUE = 100.0;
42 constexpr double DEGREES_VALUE = 360.0; // one turn means 360 deg
43 constexpr double GRADIANS_VALUE = 400.0; // one turn means 400 grad
44 const extern double RADIANS_VALUE; // one turn means 2*pi rad
45 const char ELLIPSIS[] = "...";
46
Str8ToStr16(const std::string & str)47 inline std::u16string Str8ToStr16(const std::string& str)
48 {
49 if (str == DEFAULT_STRING) {
50 return DEFAULT_USTRING;
51 }
52 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert(DEFAULT_STRING, DEFAULT_USTRING);
53 std::u16string result = convert.from_bytes(str);
54 return result == DEFAULT_USTRING ? u"" : result;
55 }
56
Str16ToStr8(const std::u16string & str)57 inline std::string Str16ToStr8(const std::u16string& str)
58 {
59 if (str == DEFAULT_USTRING) {
60 return DEFAULT_STRING;
61 }
62 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert(DEFAULT_STRING);
63 std::string result = convert.to_bytes(str);
64 return result == DEFAULT_STRING ? "" : result;
65 }
66
ToWstring(const std::string & str)67 inline std::wstring ToWstring(const std::string& str)
68 {
69 if (str == DEFAULT_STRING) {
70 return DEFAULT_WSTRING;
71 }
72 #ifdef PREVIEW
73 std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> convert(DEFAULT_STRING, DEFAULT_WSTRING);
74 #elif WINDOWS_PLATFORM
75 std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> convert(DEFAULT_STRING, DEFAULT_WSTRING);
76 #else
77 std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> convert(DEFAULT_STRING, DEFAULT_WSTRING);
78 #endif
79 std::wstring result = convert.from_bytes(str);
80 return result == DEFAULT_WSTRING ? L"" : result;
81 }
82
IsLetterOrNumberForWchar(wchar_t chr)83 inline bool IsLetterOrNumberForWchar(wchar_t chr)
84 {
85 return (chr >= L'0' && chr <= L'9') || (chr >= L'a' && chr <= L'z') || (chr >= L'A' && chr <= L'Z');
86 }
87
IsLetterOrNumberForChar16(char16_t chr)88 inline bool IsLetterOrNumberForChar16(char16_t chr)
89 {
90 return (chr >= u'0' && chr <= u'9') || (chr >= u'a' && chr <= u'z') || (chr >= u'A' && chr <= u'Z');
91 }
92
ToString(const std::wstring & str)93 inline std::string ToString(const std::wstring& str)
94 {
95 if (str == DEFAULT_WSTRING) {
96 return DEFAULT_STRING;
97 }
98 #ifdef PREVIEW
99 std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> convert(DEFAULT_STRING);
100 #elif WINDOWS_PLATFORM
101 std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> convert(DEFAULT_STRING);
102 #else
103 std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> convert(DEFAULT_STRING);
104 #endif
105 std::string result = convert.to_bytes(str);
106 return result == DEFAULT_STRING ? "" : result;
107 }
108
ToU32string(const std::string & str)109 inline std::u32string ToU32string(const std::string& str)
110 {
111 if (str == DEFAULT_STRING) {
112 return DEFAULT_U32STRING;
113 }
114 std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> convert(DEFAULT_STRING, DEFAULT_U32STRING);
115 std::u32string result = convert.from_bytes(str);
116 return result == DEFAULT_U32STRING ? U"" : result;
117 }
118
U32StringToString(const std::u32string & str)119 inline std::string U32StringToString(const std::u32string& str)
120 {
121 if (str == DEFAULT_U32STRING) {
122 return DEFAULT_STRING;
123 }
124 std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> convert(DEFAULT_STRING);
125 std::string result = convert.to_bytes(str);
126 return result == DEFAULT_STRING ? "" : result;
127 }
128
NotInUtf16Bmp(char16_t c)129 inline bool NotInUtf16Bmp(char16_t c)
130 {
131 return (c & 0xF800) == 0xD800;
132 }
133
NotInBmp(wchar_t ch)134 inline bool NotInBmp(wchar_t ch)
135 {
136 return ch >= 0xD800 && ch <= 0xDBFF;
137 }
138
IsNumber(const std::string & value)139 inline bool IsNumber(const std::string& value)
140 {
141 if (value.empty()) {
142 return false;
143 }
144 return std::all_of(value.begin(), value.end(), [](char i) { return isdigit(i); });
145 }
146
IsFloat(const std::string & s)147 inline bool IsFloat(const std::string& s)
148 {
149 if (s.empty()) {
150 return false;
151 }
152 int dot_count = 0;
153 bool all_valid = std::all_of(s.begin(), s.end(), [&](char c) {
154 if (c == '.') {
155 dot_count++;
156 return true;
157 }
158 return std::isdigit(static_cast<unsigned char>(c)) != 0;
159 });
160 if (!all_valid || dot_count > 1) {
161 return false;
162 }
163 return s != "." && s != ".." && std::any_of(s.begin(), s.end(), ::isdigit);
164 }
ReplaceSpace(std::string & data)165 inline void ReplaceSpace(std::string& data)
166 {
167 bool isFirstSpace = true;
168 auto iter = data.begin();
169 while (iter != data.end()) {
170 if (*iter == ' ') {
171 if (isFirstSpace) {
172 iter++;
173 isFirstSpace = false;
174 } else {
175 iter = data.erase(iter);
176 }
177 } else if (*iter == '\t') {
178 *iter = ' ';
179 } else {
180 isFirstSpace = true;
181 iter++;
182 }
183 }
184 }
185
ReplaceTabAndNewLine(std::string & data)186 inline void ReplaceTabAndNewLine(std::string& data)
187 {
188 for (auto& i : data) {
189 if (i == '\r' || i == '\n') {
190 i = ' ';
191 }
192 }
193 ReplaceSpace(data);
194 }
195
RestoreEscape(const std::string & src)196 inline std::string RestoreEscape(const std::string& src)
197 {
198 std::string res;
199 for (auto &c : src) {
200 switch (c) {
201 case '\n':
202 res += "\\n";
203 break;
204 case '\r':
205 res += "\\r";
206 break;
207 case '\t':
208 res += "\\t";
209 break;
210 default:
211 res.push_back(c);
212 break;
213 }
214 }
215 return res;
216 }
217
RestoreBackslash(const std::string & src)218 inline std::string RestoreBackslash(const std::string& src)
219 {
220 std::string res;
221 for (auto &c : src) {
222 if (c != '\\') {
223 res.push_back(c);
224 }
225 }
226 return res;
227 }
228
229 inline int32_t StringToInt(const std::string& value, int64_t defaultErr = 0)
230 {
231 errno = 0;
232 char* pEnd = nullptr;
233 int64_t result = std::strtol(value.c_str(), &pEnd, 10);
234 if (pEnd == value.c_str() || (result < INT_MIN || result > INT_MAX) || errno == ERANGE) {
235 return defaultErr;
236 } else {
237 return result;
238 }
239 }
240
241 inline int64_t StringToLongInt(const std::string& value, int64_t defaultErr = 0)
242 {
243 errno = 0;
244 char* pEnd = nullptr;
245 int64_t result = std::strtoll(value.c_str(), &pEnd, 10);
246 if (pEnd == value.c_str() || errno == ERANGE) {
247 return defaultErr;
248 } else {
249 return result;
250 }
251 }
252
253 inline uint64_t StringToLongUint(const std::string& value, uint64_t defaultErr = 0)
254 {
255 errno = 0;
256 char* pEnd = nullptr;
257 uint64_t result = std::strtoull(value.c_str(), &pEnd, 10);
258 if (pEnd == value.c_str() || errno == ERANGE) {
259 return defaultErr;
260 } else {
261 return result;
262 }
263 }
264
265 inline uint32_t StringToUintCheck(const std::string& value, uint32_t defaultErr = 0)
266 {
267 errno = 0;
268 char* pEnd = nullptr;
269 uint64_t result = std::strtoull(value.c_str(), &pEnd, 10);
270 if ((pEnd == value.c_str()) || ((pEnd != nullptr) && (*pEnd != '\0')) || result > UINT32_MAX || errno == ERANGE) {
271 return defaultErr;
272 } else {
273 return result;
274 }
275 }
276
277 inline uint32_t StringToUint(const std::string& value, uint32_t defaultErr = 0)
278 {
279 errno = 0;
280 char* pEnd = nullptr;
281 uint64_t result = std::strtoull(value.c_str(), &pEnd, 10);
282 if (pEnd == value.c_str() || result > UINT32_MAX || errno == ERANGE) {
283 return defaultErr;
284 } else {
285 return result;
286 }
287 }
288
289 // generic string to double value method without success check
StringToDouble(const std::string & value)290 inline double StringToDouble(const std::string& value)
291 {
292 char* pEnd = nullptr;
293 errno = 0;
294 double result = std::strtod(value.c_str(), &pEnd);
295 if (pEnd == value.c_str() || errno == ERANGE) {
296 return 0.0;
297 } else {
298 return result;
299 }
300 }
301 // string to double method with success check, and support for parsing number string with percentage case
StringToDouble(const std::string & value,double & result)302 inline bool StringToDouble(const std::string& value, double& result)
303 {
304 errno = 0;
305 char* pEnd = nullptr;
306 double res = std::strtod(value.c_str(), &pEnd);
307 if (pEnd == value.c_str() || errno == ERANGE) {
308 return false;
309 } else if (pEnd != nullptr) {
310 if (std::strcmp(pEnd, "%") == 0) {
311 result = res / PERCENT_VALUE;
312 return true;
313 } else if (std::strcmp(pEnd, "") == 0) {
314 result = res;
315 return true;
316 }
317 }
318 return false;
319 }
320
StringToFloat(const std::string & value)321 inline float StringToFloat(const std::string& value)
322 {
323 errno = 0;
324 char* pEnd = nullptr;
325 float result = std::strtof(value.c_str(), &pEnd);
326 if (pEnd == value.c_str() || errno == ERANGE) {
327 return 0.0f;
328 } else {
329 return result;
330 }
331 }
332
333 static Dimension StringToDimensionWithUnit(const std::string& value, DimensionUnit defaultUnit = DimensionUnit::PX,
334 float defaultValue = 0.0f, bool isCalc = false)
335 {
336 errno = 0;
337 if (std::strcmp(value.c_str(), "auto") == 0) {
338 return Dimension(defaultValue, DimensionUnit::AUTO);
339 }
340 char* pEnd = nullptr;
341 double result = std::strtod(value.c_str(), &pEnd);
342 if (pEnd == value.c_str() || errno == ERANGE) {
343 return Dimension(defaultValue, defaultUnit);
344 }
345 if (pEnd != nullptr) {
346 if (std::strcmp(pEnd, "%") == 0) {
347 // Parse percent, transfer from [0, 100] to [0, 1]
348 return Dimension(result / 100.0, DimensionUnit::PERCENT);
349 }
350 if (std::strcmp(pEnd, "px") == 0) {
351 return Dimension(result, DimensionUnit::PX);
352 }
353 if (std::strcmp(pEnd, "vp") == 0) {
354 return Dimension(result, DimensionUnit::VP);
355 }
356 if (std::strcmp(pEnd, "fp") == 0) {
357 return Dimension(result, DimensionUnit::FP);
358 }
359 if (std::strcmp(pEnd, "lpx") == 0) {
360 return Dimension(result, DimensionUnit::LPX);
361 }
362 if ((std::strcmp(pEnd, "\0") == 0) && isCalc) {
363 return Dimension(result, DimensionUnit::NONE);
364 }
365 if (isCalc) {
366 return Dimension(result, DimensionUnit::INVALID);
367 }
368 }
369 return Dimension(result, defaultUnit);
370 }
371
372 inline CalcDimension StringToCalcDimension(
373 const std::string& value, bool useVp = false, DimensionUnit defaultUnit = DimensionUnit::PX)
374 {
375 if (value.find("calc") != std::string::npos) {
376 return CalcDimension(value, DimensionUnit::CALC);
377 } else {
378 if (useVp) {
379 return StringToDimensionWithUnit(value, DimensionUnit::VP);
380 }
381 return StringToDimensionWithUnit(value, defaultUnit);
382 }
383 }
384
385 inline Dimension StringToDimension(const std::string& value, bool useVp = false)
386 {
387 return StringToDimensionWithUnit(value, useVp ? DimensionUnit::VP : DimensionUnit::PX);
388 }
389
StringToDimensionWithThemeValue(const std::string & value,bool useVp,const Dimension & themeValue)390 inline Dimension StringToDimensionWithThemeValue(const std::string& value, bool useVp, const Dimension& themeValue)
391 {
392 errno = 0;
393 char* pEnd = nullptr;
394 std::strtod(value.c_str(), &pEnd);
395 if (pEnd == value.c_str() || errno == ERANGE) {
396 return themeValue;
397 }
398
399 return StringToDimensionWithUnit(value, useVp ? DimensionUnit::VP : DimensionUnit::PX);
400 }
401
402 static bool StringToDimensionWithUnitNG(const std::string& value, Dimension& dimensionResult,
403 DimensionUnit defaultUnit = DimensionUnit::PX, float defaultValue = 0.0f, bool isCalc = false)
404 {
405 errno = 0;
406 if (std::strcmp(value.c_str(), "auto") == 0) {
407 dimensionResult = Dimension(defaultValue, DimensionUnit::AUTO);
408 return true;
409 }
410 char* pEnd = nullptr;
411 double result = std::strtod(value.c_str(), &pEnd);
412 if (pEnd == value.c_str() || errno == ERANGE) {
413 dimensionResult = Dimension(defaultValue, defaultUnit);
414 return false;
415 }
416 if (pEnd != nullptr) {
417 if (std::strcmp(pEnd, "%") == 0) {
418 // Parse percent, transfer from [0, 100] to [0, 1]
419 dimensionResult = Dimension(result / 100.0, DimensionUnit::PERCENT);
420 return true;
421 }
422 if (std::strcmp(pEnd, "px") == 0) {
423 dimensionResult = Dimension(result, DimensionUnit::PX);
424 return true;
425 }
426 if (std::strcmp(pEnd, "vp") == 0) {
427 dimensionResult = Dimension(result, DimensionUnit::VP);
428 return true;
429 }
430 if (std::strcmp(pEnd, "fp") == 0) {
431 dimensionResult = Dimension(result, DimensionUnit::FP);
432 return true;
433 }
434 if (std::strcmp(pEnd, "lpx") == 0) {
435 dimensionResult = Dimension(result, DimensionUnit::LPX);
436 return true;
437 }
438 if ((std::strcmp(pEnd, "\0") == 0) && isCalc) {
439 dimensionResult = Dimension(result, DimensionUnit::NONE);
440 return true;
441 }
442 if (isCalc) {
443 dimensionResult = Dimension(result, DimensionUnit::INVALID);
444 return true;
445 }
446 if ((std::strcmp(pEnd, "\0") != 0)) {
447 dimensionResult = Dimension(result, DimensionUnit::NONE);
448 return false;
449 }
450 }
451 dimensionResult = Dimension(result, defaultUnit);
452 return true;
453 }
454
455 inline bool StringToCalcDimensionNG(
456 const std::string& value, CalcDimension& result, bool useVp = false,
457 DimensionUnit defaultUnit = DimensionUnit::PX)
458 {
459 if (value.find("calc") != std::string::npos) {
460 result = CalcDimension(value, DimensionUnit::CALC);
461 return true;
462 } else {
463 return StringToDimensionWithUnitNG(value, result, useVp ? DimensionUnit::VP : defaultUnit);
464 }
465 }
466
ReplaceChar(std::string str,char old_char,char new_char)467 inline std::string ReplaceChar(std::string str, char old_char, char new_char)
468 {
469 for (char& it : str) {
470 if (it == old_char) {
471 it = new_char;
472 }
473 }
474 return str;
475 }
476
StringToDegree(const std::string & value)477 inline double StringToDegree(const std::string& value)
478 {
479 // https://developer.mozilla.org/zh-CN/docs/Web/CSS/angle
480
481 errno = 0;
482 char* pEnd = nullptr;
483 double result = std::strtod(value.c_str(), &pEnd);
484 if (pEnd == value.c_str() || errno == ERANGE) {
485 return 0.0;
486 } else if (pEnd) {
487 if ((std::strcmp(pEnd, "deg")) == 0) {
488 return result;
489 } else if (std::strcmp(pEnd, "grad") == 0) {
490 return result / GRADIANS_VALUE * DEGREES_VALUE;
491 } else if (std::strcmp(pEnd, "rad") == 0) {
492 return result / RADIANS_VALUE * DEGREES_VALUE;
493 } else if (std::strcmp(pEnd, "turn") == 0) {
494 return result * DEGREES_VALUE;
495 }
496 }
497 return StringToDouble(value);
498 }
499
500 // StringToDegree with check. If the string is valid, change result and return true, otherwise return false.
StringToDegree(const std::string & value,double & result)501 inline bool StringToDegree(const std::string& value, double& result)
502 {
503 errno = 0;
504 char* pEnd = nullptr;
505 double temp = std::strtod(value.c_str(), &pEnd);
506 if (pEnd == value.c_str() || errno == ERANGE) {
507 return false;
508 } else if (pEnd) {
509 if (*pEnd == '\0') {
510 result = temp;
511 return true;
512 }
513 if (std::strcmp(pEnd, "deg") == 0) {
514 result = temp;
515 return true;
516 }
517 if (std::strcmp(pEnd, "grad") == 0) {
518 result = temp / GRADIANS_VALUE * DEGREES_VALUE;
519 return true;
520 }
521 if (std::strcmp(pEnd, "rad") == 0) {
522 result = temp / RADIANS_VALUE * DEGREES_VALUE;
523 return true;
524 }
525 if (std::strcmp(pEnd, "turn") == 0) {
526 result = temp * DEGREES_VALUE;
527 return true;
528 }
529 }
530 return false;
531 }
532
533 template<class T>
StringSplitter(const std::string & source,char delimiter,T (* func)(const std::string &),std::vector<T> & out)534 inline void StringSplitter(
535 const std::string& source, char delimiter, T (*func)(const std::string&), std::vector<T>& out)
536 {
537 out.erase(out.begin(), out.end());
538
539 if (source.empty()) {
540 return;
541 }
542
543 std::size_t startIndex = 0;
544 for (std::size_t index = 0; index < source.size(); index++) {
545 if (source[index] != delimiter) {
546 continue;
547 }
548
549 if (index > startIndex) {
550 out.emplace_back(func(source.substr(startIndex, index - startIndex)));
551 }
552 startIndex = index + 1;
553 }
554
555 if (startIndex < source.size()) {
556 out.emplace_back(func(source.substr(startIndex)));
557 }
558 }
559
ParseStringToArray(const std::string & input,std::vector<float> & output)560 inline bool ParseStringToArray(const std::string& input, std::vector<float>& output)
561 {
562 std::istringstream iss(StringUtils::ReplaceChar(input, ',', ' '));
563 std::string token;
564
565 while (iss >> token) {
566 double value;
567 if (!StringToDouble(token, value)) {
568 return false;
569 }
570 output.emplace_back(value);
571 }
572
573 return true;
574 }
575
StringSplitter(const std::string & source,char delimiter,std::vector<std::string> & out)576 inline void StringSplitter(const std::string& source, char delimiter, std::vector<std::string>& out)
577 {
578 using Func = std::string (*)(const std::string&);
579 Func func = [](const std::string& value) { return value; };
580 StringSplitter(source, delimiter, func, out);
581 }
582
StringSplitter(const std::string & source,char delimiter,std::vector<double> & out)583 inline void StringSplitter(const std::string& source, char delimiter, std::vector<double>& out)
584 {
585 using Func = double (*)(const std::string&);
586 Func func = [](const std::string& value) { return StringToDouble(value); };
587 StringSplitter(source, delimiter, func, out);
588 }
589
StringSplitter(const std::string & source,char delimiter,std::vector<float> & out)590 inline void StringSplitter(const std::string& source, char delimiter, std::vector<float>& out)
591 {
592 using Func = float (*)(const std::string&);
593 Func func = [](const std::string& value) { return StringToFloat(value); };
594 StringSplitter(source, delimiter, func, out);
595 }
596
StringSplitter(const std::string & source,char delimiter,std::vector<int> & out)597 inline void StringSplitter(const std::string& source, char delimiter, std::vector<int>& out)
598 {
599 using Func = int32_t (*)(const std::string&);
600 Func func = [](const std::string& value) { return StringToInt(value); };
601 StringSplitter(source, delimiter, func, out);
602 }
603
StringSplitter(const std::string & source,char delimiter,std::vector<Dimension> & out)604 inline void StringSplitter(const std::string& source, char delimiter, std::vector<Dimension>& out)
605 {
606 using Func = Dimension (*)(const std::string&);
607 Func func = [](const std::string& value) { return StringToDimension(value); };
608 StringSplitter(source, delimiter, func, out);
609 }
610
611 inline std::string DoubleToString(double value, int32_t precision = 2)
612 {
613 std::ostringstream result;
614 result.precision(precision);
615 if (NearEqual(value, Infinity<double>())) {
616 result << "Infinity";
617 } else {
618 result << std::fixed << value;
619 }
620 return result.str();
621 }
622
DeleteAllMark(std::string & str,const char mark)623 inline void DeleteAllMark(std::string& str, const char mark)
624 {
625 str.erase(std::remove(str.begin(), str.end(), mark), str.end());
626 }
627
628 inline std::string TrimStr(const std::string& str, char cTrim = ' ')
629 {
630 auto firstPos = str.find_first_not_of(cTrim);
631 if (firstPos == std::string::npos) {
632 return str;
633 }
634 auto endPos = str.find_last_not_of(cTrim);
635 return str.substr(firstPos, endPos - firstPos + 1);
636 }
637
638 inline void TrimStrLeadingAndTrailing(std::string& str, char cTrim = ' ')
639 {
640 auto firstIndexNotOfSpace = str.find_first_not_of(" ");
641 if (firstIndexNotOfSpace == std::string::npos) {
642 str = "";
643 return;
644 }
645 str.erase(0, firstIndexNotOfSpace);
646 auto lastIndexNotOfSpace = str.find_last_not_of(" ");
647 if (lastIndexNotOfSpace == std::string::npos) {
648 str = "";
649 return;
650 }
651 str.erase(lastIndexNotOfSpace + 1);
652 }
653
654 inline void SplitStr(
655 const std::string& str, const std::string& sep, std::vector<std::string>& out, bool needTrim = true)
656 {
657 out.erase(out.begin(), out.end());
658
659 if (str.empty() || sep.empty()) {
660 return;
661 }
662
663 std::string strPart;
664 std::string::size_type startPos = 0;
665 std::string::size_type pos = str.find_first_of(sep, startPos);
666 while (pos != std::string::npos) {
667 if (pos > startPos) {
668 strPart = needTrim ? TrimStr(str.substr(startPos, pos - startPos)) : str.substr(startPos, pos - startPos);
669 out.emplace_back(std::move(strPart));
670 }
671 startPos = pos + sep.size();
672 pos = str.find_first_of(sep, startPos);
673 }
674
675 if (startPos < str.size()) {
676 strPart = needTrim ? TrimStr(str.substr(startPos)) : str.substr(startPos);
677 out.emplace_back(std::move(strPart));
678 }
679 }
680
681 inline void SplitStr(const std::string& str, const std::string& sep, std::vector<Dimension>& out, bool needTrim = true)
682 {
683 out.erase(out.begin(), out.end());
684 if (str.empty() || sep.empty()) {
685 return;
686 }
687 std::string strPart;
688 std::string::size_type startPos = 0;
689 std::string::size_type pos = str.find_first_of(sep, startPos);
690 while (pos != std::string::npos) {
691 if (pos > startPos) {
692 strPart = needTrim ? TrimStr(str.substr(startPos, pos - startPos)) : str.substr(startPos, pos - startPos);
693 if (!strPart.empty()) {
694 out.emplace_back(StringToDimension(std::move(strPart)));
695 }
696 }
697 startPos = pos + sep.size();
698 pos = str.find_first_of(sep, startPos);
699 }
700 if (startPos < str.size()) {
701 strPart = needTrim ? TrimStr(str.substr(startPos)) : str.substr(startPos);
702 if (!strPart.empty()) {
703 out.emplace_back(StringToDimension(std::move(strPart)));
704 }
705 }
706 }
707
CStringEqual(const char * first,const char * second)708 inline bool CStringEqual(const char* first, const char* second)
709 {
710 if (first == nullptr && second == nullptr) {
711 return true;
712 }
713 if (first && second) {
714 return std::strcmp(first, second) == 0;
715 }
716 return false;
717 }
718
719 const std::string ACE_FORCE_EXPORT FormatString(const char* fmt, ...);
720
StartWith(const std::string & dst,const std::string & prefix)721 inline bool StartWith(const std::string& dst, const std::string& prefix)
722 {
723 return dst.compare(0, prefix.size(), prefix) == 0;
724 }
725
StartWith(const std::string & str,const char * prefix,size_t prefixLen)726 inline bool StartWith(const std::string& str, const char* prefix, size_t prefixLen)
727 {
728 return ((str.length() >= prefixLen) && (str.compare(0, prefixLen, prefix) == 0));
729 }
730
EndWith(const std::string & dst,const std::string & suffix)731 inline bool EndWith(const std::string& dst, const std::string& suffix)
732 {
733 return (dst.size() >= suffix.size()) && dst.compare(dst.size() - suffix.size(), suffix.size(), suffix) == 0;
734 }
735
EndWith(const std::string & str,const char * suffix,size_t suffixLen)736 inline bool EndWith(const std::string& str, const char* suffix, size_t suffixLen)
737 {
738 size_t len = str.length();
739 return ((len >= suffixLen) && (str.compare(len - suffixLen, suffixLen, suffix) == 0));
740 }
741
742 template<typename T>
TransformStrCase(T & str,int32_t textCase)743 inline void TransformStrCase(T& str, int32_t textCase)
744 {
745 if (str.empty()) {
746 return;
747 }
748
749 switch (textCase) {
750 case TEXT_CASE_LOWERCASE:
751 transform(str.begin(), str.end(), str.begin(), ::tolower);
752 break;
753 case TEXT_CASE_UPPERCASE:
754 transform(str.begin(), str.end(), str.begin(), ::toupper);
755 break;
756 default:
757 break;
758 }
759 }
760
761 ACE_FORCE_EXPORT bool IsAscii(const std::string& str);
762 } // namespace OHOS::Ace::StringUtils
763
764 #endif // FOUNDATION_ACE_FRAMEWORKS_BASE_UTILS_STRING_UTILS_H
765