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