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