• 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 
ToString(const std::wstring & str)77 inline std::string ToString(const std::wstring& str)
78 {
79     if (str == DEFAULT_WSTRING) {
80         return DEFAULT_STRING;
81     }
82 #ifdef WINDOWS_PLATFORM
83     std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> convert(DEFAULT_STRING);
84 #else
85     std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> convert(DEFAULT_STRING);
86 #endif
87     std::string result = convert.to_bytes(str);
88     return result == DEFAULT_STRING ? "" : result;
89 }
90 
NotInUtf16Bmp(char16_t c)91 inline bool NotInUtf16Bmp(char16_t c)
92 {
93     return (c & 0xF800) == 0xD800;
94 }
95 
NotInBmp(wchar_t ch)96 inline bool NotInBmp(wchar_t ch)
97 {
98     return ch >= 0xD800 && ch <= 0xDBFF;
99 }
100 
IsNumber(const std::string & value)101 inline bool IsNumber(const std::string& value)
102 {
103     if (value.empty()) {
104         return false;
105     }
106     return std::all_of(value.begin(), value.end(), [](char i) { return isdigit(i); });
107 }
108 
ReplaceSpace(std::string & data)109 inline void ReplaceSpace(std::string& data)
110 {
111     bool isFirstSpace = true;
112     auto iter = data.begin();
113     while (iter != data.end()) {
114         if (*iter == ' ') {
115             if (isFirstSpace) {
116                 iter++;
117                 isFirstSpace = false;
118             } else {
119                 iter = data.erase(iter);
120             }
121         } else if (*iter == '\t') {
122             *iter = ' ';
123         } else {
124             isFirstSpace = true;
125             iter++;
126         }
127     }
128 }
129 
ReplaceTabAndNewLine(std::string & data)130 inline void ReplaceTabAndNewLine(std::string& data)
131 {
132     for (auto& i : data) {
133         if (i == '\r' || i == '\n') {
134             i = ' ';
135         }
136     }
137     ReplaceSpace(data);
138 }
139 
StringToInt(const std::string & value)140 inline int32_t StringToInt(const std::string& value)
141 {
142     errno = 0;
143     char* pEnd = nullptr;
144     int64_t result = std::strtol(value.c_str(), &pEnd, 10);
145     if (pEnd == value.c_str() || (result < INT_MIN || result > INT_MAX) || errno == ERANGE) {
146         return 0;
147     } else {
148         return result;
149     }
150 }
151 
StringToLongInt(const std::string & value)152 inline int64_t StringToLongInt(const std::string& value)
153 {
154     errno = 0;
155     char* pEnd = nullptr;
156     int64_t result = std::strtoll(value.c_str(), &pEnd, 10);
157     if (pEnd == value.c_str() || errno == ERANGE) {
158         return 0;
159     } else {
160         return result;
161     }
162 }
163 
164 inline uint32_t StringToUint(const std::string& value, uint32_t defaultErr = 0)
165 {
166     errno = 0;
167     char* pEnd = nullptr;
168     uint64_t result = std::strtoull(value.c_str(), &pEnd, 10);
169     if (pEnd == value.c_str() || result > UINT32_MAX || errno == ERANGE) {
170         return defaultErr;
171     } else {
172         return result;
173     }
174 }
175 // generic string to double value method without success check
StringToDouble(const std::string & value)176 inline double StringToDouble(const std::string& value)
177 {
178     char* pEnd = nullptr;
179     double result = std::strtod(value.c_str(), &pEnd);
180     if (pEnd == value.c_str() || errno == ERANGE) {
181         return 0.0;
182     } else {
183         return result;
184     }
185 }
186 // string to double method with success check, and support for parsing number string with percentage case
StringToDouble(const std::string & value,double & result)187 inline bool StringToDouble(const std::string& value, double& result)
188 {
189     char* pEnd = nullptr;
190     double res = std::strtod(value.c_str(), &pEnd);
191     if (pEnd == value.c_str() || errno == ERANGE) {
192         return false;
193     } else if (pEnd != nullptr) {
194         if (std::strcmp(pEnd, "%") == 0) {
195             result = res / PERCENT_VALUE;
196             return true;
197         } else if (std::strcmp(pEnd, "") == 0) {
198             result = res;
199             return true;
200         }
201     }
202     return false;
203 }
204 
StringToFloat(const std::string & value)205 inline float StringToFloat(const std::string& value)
206 {
207     char* pEnd = nullptr;
208     float result = std::strtof(value.c_str(), &pEnd);
209     if (pEnd == value.c_str() || errno == ERANGE) {
210         return 0.0f;
211     } else {
212         return result;
213     }
214 }
215 
216 inline Dimension StringToDimensionWithUnit(
217     const std::string& value, DimensionUnit defaultUnit = DimensionUnit::PX, float defaultValue = 0.0f)
218 {
219     errno = 0;
220     if (std::strcmp(value.c_str(), "auto") == 0) {
221         return Dimension(defaultValue, DimensionUnit::AUTO);
222     }
223     char* pEnd = nullptr;
224     double result = std::strtod(value.c_str(), &pEnd);
225     if (pEnd == value.c_str() || errno == ERANGE) {
226         return Dimension(defaultValue, defaultUnit);
227     }
228     if (pEnd != nullptr) {
229         if (std::strcmp(pEnd, "%") == 0) {
230             // Parse percent, transfer from [0, 100] to [0, 1]
231             return Dimension(result / 100.0, DimensionUnit::PERCENT);
232         }
233         if (std::strcmp(pEnd, "px") == 0) {
234             return Dimension(result, DimensionUnit::PX);
235         }
236         if (std::strcmp(pEnd, "vp") == 0) {
237             return Dimension(result, DimensionUnit::VP);
238         }
239         if (std::strcmp(pEnd, "fp") == 0) {
240             return Dimension(result, DimensionUnit::FP);
241         }
242         if ((pEnd) && (std::strcmp(pEnd, "lpx") == 0)) {
243             return Dimension(result, DimensionUnit::LPX);
244         }
245     }
246     return Dimension(result, defaultUnit);
247 }
248 
249 inline CalcDimension StringToCalcDimension(const std::string& value, bool useVp = false)
250 {
251     if (value.find("calc") != std::string::npos) {
252         return CalcDimension(value, DimensionUnit::CALC);
253     } else {
254         return StringToDimensionWithUnit(value, useVp ? DimensionUnit::VP : DimensionUnit::PX);
255     }
256 }
257 
258 inline Dimension StringToDimension(const std::string& value, bool useVp = false)
259 {
260     return StringToDimensionWithUnit(value, useVp ? DimensionUnit::VP : DimensionUnit::PX);
261 }
262 
StringToDimensionWithThemeValue(const std::string & value,bool useVp,const Dimension & themeValue)263 inline Dimension StringToDimensionWithThemeValue(const std::string& value, bool useVp, const Dimension& themeValue)
264 {
265     errno = 0;
266     char* pEnd = nullptr;
267     std::strtod(value.c_str(), &pEnd);
268     if (pEnd == value.c_str() || errno == ERANGE) {
269         return themeValue;
270     }
271 
272     return StringToDimensionWithUnit(value, useVp ? DimensionUnit::VP : DimensionUnit::PX);
273 }
274 
StringToDegree(const std::string & value)275 inline double StringToDegree(const std::string& value)
276 {
277     // https://developer.mozilla.org/zh-CN/docs/Web/CSS/angle
278     constexpr static double DEGREES = 360.0;
279     constexpr static double GRADIANS = 400.0;
280     constexpr static double RADIUS = 2 * M_PI;
281 
282     errno = 0;
283     char* pEnd = nullptr;
284     double result = std::strtod(value.c_str(), &pEnd);
285     if (pEnd == value.c_str() || errno == ERANGE) {
286         return 0.0;
287     } else if (pEnd) {
288         if ((std::strcmp(pEnd, "deg")) == 0) {
289             return result;
290         } else if (std::strcmp(pEnd, "grad") == 0) {
291             return result / GRADIANS * DEGREES;
292         } else if (std::strcmp(pEnd, "rad") == 0) {
293             return result / RADIUS * DEGREES;
294         } else if (std::strcmp(pEnd, "turn") == 0) {
295             return result * DEGREES;
296         }
297     }
298     return StringToDouble(value);
299 }
300 
301 template<class T>
StringSplitter(const std::string & source,char delimiter,T (* func)(const std::string &),std::vector<T> & out)302 inline void StringSplitter(
303     const std::string& source, char delimiter, T (*func)(const std::string&), std::vector<T>& out)
304 {
305     out.erase(out.begin(), out.end());
306 
307     if (source.empty()) {
308         return;
309     }
310 
311     std::size_t startIndex = 0;
312     for (std::size_t index = 0; index < source.size(); index++) {
313         if (source[index] != delimiter) {
314             continue;
315         }
316 
317         if (index > startIndex) {
318             out.emplace_back(func(source.substr(startIndex, index - startIndex)));
319         }
320         startIndex = index + 1;
321     }
322 
323     if (startIndex < source.size()) {
324         out.emplace_back(func(source.substr(startIndex)));
325     }
326 }
327 
StringSplitter(const std::string & source,char delimiter,std::vector<std::string> & out)328 inline void StringSplitter(const std::string& source, char delimiter, std::vector<std::string>& out)
329 {
330     using Func = std::string (*)(const std::string&);
331     Func func = [](const std::string& value) { return value; };
332     StringSplitter(source, delimiter, func, out);
333 }
334 
StringSplitter(const std::string & source,char delimiter,std::vector<double> & out)335 inline void StringSplitter(const std::string& source, char delimiter, std::vector<double>& out)
336 {
337     using Func = double (*)(const std::string&);
338     Func func = [](const std::string& value) { return StringToDouble(value); };
339     StringSplitter(source, delimiter, func, out);
340 }
341 
StringSplitter(const std::string & source,char delimiter,std::vector<float> & out)342 inline void StringSplitter(const std::string& source, char delimiter, std::vector<float>& out)
343 {
344     using Func = float (*)(const std::string&);
345     Func func = [](const std::string& value) { return StringToFloat(value); };
346     StringSplitter(source, delimiter, func, out);
347 }
348 
StringSplitter(const std::string & source,char delimiter,std::vector<int> & out)349 inline void StringSplitter(const std::string& source, char delimiter, std::vector<int>& out)
350 {
351     using Func = int32_t (*)(const std::string&);
352     Func func = [](const std::string& value) { return StringToInt(value); };
353     StringSplitter(source, delimiter, func, out);
354 }
355 
StringSplitter(const std::string & source,char delimiter,std::vector<Dimension> & out)356 inline void StringSplitter(const std::string& source, char delimiter, std::vector<Dimension>& out)
357 {
358     using Func = Dimension (*)(const std::string&);
359     Func func = [](const std::string& value) { return StringToDimension(value); };
360     StringSplitter(source, delimiter, func, out);
361 }
362 
363 inline std::string DoubleToString(double value, int32_t precision = 2)
364 {
365     std::ostringstream result;
366     result.precision(precision);
367     if (NearEqual(value, Infinity<double>())) {
368         result << "Infinity";
369     } else {
370         result << std::fixed << value;
371     }
372     return result.str();
373 }
374 
DeleteAllMark(std::string & str,const char mark)375 inline void DeleteAllMark(std::string& str, const char mark)
376 {
377     str.erase(std::remove(str.begin(), str.end(), mark), str.end());
378 }
379 
380 inline std::string TrimStr(const std::string& str, char cTrim = ' ')
381 {
382     auto firstPos = str.find_first_not_of(cTrim);
383     if (firstPos == std::string::npos) {
384         return str;
385     }
386     auto endPos = str.find_last_not_of(cTrim);
387     return str.substr(firstPos, endPos - firstPos + 1);
388 }
389 
390 inline void TrimStrLeadingAndTrailing(std::string& str, char cTrim = ' ')
391 {
392     auto firstIndexNotOfSpace = str.find_first_not_of(" ");
393     if (firstIndexNotOfSpace == std::string::npos) {
394         str = "";
395         return;
396     }
397     str.erase(0, firstIndexNotOfSpace);
398     auto lastIndexNotOfSpace = str.find_last_not_of(" ");
399     if (lastIndexNotOfSpace == std::string::npos) {
400         str = "";
401         return;
402     }
403     str.erase(lastIndexNotOfSpace + 1);
404 }
405 
406 inline void SplitStr(
407     const std::string& str, const std::string& sep, std::vector<std::string>& out, bool needTrim = true)
408 {
409     out.erase(out.begin(), out.end());
410 
411     if (str.empty() || sep.empty()) {
412         return;
413     }
414 
415     std::string strPart;
416     std::string::size_type startPos = 0;
417     std::string::size_type pos = str.find_first_of(sep, startPos);
418     while (pos != std::string::npos) {
419         if (pos > startPos) {
420             strPart = needTrim ? TrimStr(str.substr(startPos, pos - startPos)) : str.substr(startPos, pos - startPos);
421             out.emplace_back(std::move(strPart));
422         }
423         startPos = pos + sep.size();
424         pos = str.find_first_of(sep, startPos);
425     }
426 
427     if (startPos < str.size()) {
428         strPart = needTrim ? TrimStr(str.substr(startPos)) : str.substr(startPos);
429         out.emplace_back(std::move(strPart));
430     }
431 }
432 
433 inline void SplitStr(const std::string& str, const std::string& sep, std::vector<Dimension>& out, bool needTrim = true)
434 {
435     out.erase(out.begin(), out.end());
436     if (str.empty() || sep.empty()) {
437         return;
438     }
439     std::string strPart;
440     std::string::size_type startPos = 0;
441     std::string::size_type pos = str.find_first_of(sep, startPos);
442     while (pos != std::string::npos) {
443         if (pos > startPos) {
444             strPart = needTrim ? TrimStr(str.substr(startPos, pos - startPos)) : str.substr(startPos, pos - startPos);
445             if (!strPart.empty()) {
446                 out.emplace_back(StringToDimension(std::move(strPart)));
447             }
448         }
449         startPos = pos + sep.size();
450         pos = str.find_first_of(sep, startPos);
451     }
452     if (startPos < str.size()) {
453         strPart = needTrim ? TrimStr(str.substr(startPos)) : str.substr(startPos);
454         if (!strPart.empty()) {
455             out.emplace_back(StringToDimension(std::move(strPart)));
456         }
457     }
458 }
459 
460 const std::string ACE_EXPORT FormatString(const char* fmt, ...);
461 
StartWith(const std::string & dst,const std::string & prefix)462 inline bool StartWith(const std::string& dst, const std::string& prefix)
463 {
464     return dst.compare(0, prefix.size(), prefix) == 0;
465 }
466 
StartWith(const std::string & str,const char * prefix,size_t prefixLen)467 inline bool StartWith(const std::string& str, const char* prefix, size_t prefixLen)
468 {
469     return ((str.length() >= prefixLen) && (str.compare(0, prefixLen, prefix) == 0));
470 }
471 
EndWith(const std::string & dst,const std::string & suffix)472 inline bool EndWith(const std::string& dst, const std::string& suffix)
473 {
474     return (dst.size() >= suffix.size()) && dst.compare(dst.size() - suffix.size(), suffix.size(), suffix) == 0;
475 }
476 
EndWith(const std::string & str,const char * suffix,size_t suffixLen)477 inline bool EndWith(const std::string& str, const char* suffix, size_t suffixLen)
478 {
479     size_t len = str.length();
480     return ((len >= suffixLen) && (str.compare(len - suffixLen, suffixLen, suffix) == 0));
481 }
482 
TransformStrCase(std::string & str,int32_t textCase)483 inline void TransformStrCase(std::string& str, int32_t textCase)
484 {
485     if (str.empty()) {
486         return;
487     }
488 
489     switch (textCase) {
490         case TEXT_CASE_LOWERCASE:
491             transform(str.begin(), str.end(), str.begin(), ::tolower);
492             break;
493         case TEXT_CASE_UPPERCASE:
494             transform(str.begin(), str.end(), str.begin(), ::toupper);
495             break;
496         default:
497             break;
498     }
499 }
500 
501 } // namespace OHOS::Ace::StringUtils
502 
503 #endif // FOUNDATION_ACE_FRAMEWORKS_BASE_UTILS_STRING_UTILS_H
504