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