• 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 static Dimension StringToDimensionWithUnit(const std::string& value, DimensionUnit defaultUnit = DimensionUnit::PX,
217     float defaultValue = 0.0f, bool isCalc = false)
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 (std::strcmp(pEnd, "lpx") == 0) {
243             return Dimension(result, DimensionUnit::LPX);
244         }
245         if ((std::strcmp(pEnd, "\0") == 0) && isCalc) {
246             return Dimension(result, DimensionUnit::NONE);
247         }
248         if (isCalc) {
249             return Dimension(result, DimensionUnit::INVALID);
250         }
251     }
252     return Dimension(result, defaultUnit);
253 }
254 
255 inline CalcDimension StringToCalcDimension(
256     const std::string& value, bool useVp = false, DimensionUnit defaultUnit = DimensionUnit::PX)
257 {
258     if (value.find("calc") != std::string::npos) {
259         LOGI("StringToCalcDimension calc value = %{public}s", value.c_str());
260         return CalcDimension(value, DimensionUnit::CALC);
261     } else {
262         if (useVp) {
263             return StringToDimensionWithUnit(value, DimensionUnit::VP);
264         }
265         return StringToDimensionWithUnit(value, defaultUnit);
266     }
267 }
268 
269 inline Dimension StringToDimension(const std::string& value, bool useVp = false)
270 {
271     return StringToDimensionWithUnit(value, useVp ? DimensionUnit::VP : DimensionUnit::PX);
272 }
273 
StringToDimensionWithThemeValue(const std::string & value,bool useVp,const Dimension & themeValue)274 inline Dimension StringToDimensionWithThemeValue(const std::string& value, bool useVp, const Dimension& themeValue)
275 {
276     errno = 0;
277     char* pEnd = nullptr;
278     std::strtod(value.c_str(), &pEnd);
279     if (pEnd == value.c_str() || errno == ERANGE) {
280         return themeValue;
281     }
282 
283     return StringToDimensionWithUnit(value, useVp ? DimensionUnit::VP : DimensionUnit::PX);
284 }
285 
286 static bool StringToDimensionWithUnitNG(const std::string& value, Dimension& dimensionResult,
287     DimensionUnit defaultUnit = DimensionUnit::PX, float defaultValue = 0.0f, bool isCalc = false)
288 {
289     errno = 0;
290     if (std::strcmp(value.c_str(), "auto") == 0) {
291         dimensionResult = Dimension(defaultValue, DimensionUnit::AUTO);
292         return true;
293     }
294     char* pEnd = nullptr;
295     double result = std::strtod(value.c_str(), &pEnd);
296     if (pEnd == value.c_str() || errno == ERANGE) {
297         dimensionResult = Dimension(defaultValue, defaultUnit);
298         return false;
299     }
300     if (pEnd != nullptr) {
301         if (std::strcmp(pEnd, "%") == 0) {
302             // Parse percent, transfer from [0, 100] to [0, 1]
303             dimensionResult = Dimension(result / 100.0, DimensionUnit::PERCENT);
304             return true;
305         }
306         if (std::strcmp(pEnd, "px") == 0) {
307             dimensionResult = Dimension(result, DimensionUnit::PX);
308             return true;
309         }
310         if (std::strcmp(pEnd, "vp") == 0) {
311             dimensionResult = Dimension(result, DimensionUnit::VP);
312             return true;
313         }
314         if (std::strcmp(pEnd, "fp") == 0) {
315             dimensionResult = Dimension(result, DimensionUnit::FP);
316             return true;
317         }
318         if (std::strcmp(pEnd, "lpx") == 0) {
319             dimensionResult = Dimension(result, DimensionUnit::LPX);
320             return true;
321         }
322         if ((std::strcmp(pEnd, "\0") == 0) && isCalc) {
323             dimensionResult = Dimension(result, DimensionUnit::NONE);
324             return true;
325         }
326         if (isCalc) {
327             dimensionResult = Dimension(result, DimensionUnit::INVALID);
328             return true;
329         }
330         if ((std::strcmp(pEnd, "\0") != 0)) {
331             dimensionResult = Dimension(result, DimensionUnit::NONE);
332             return false;
333         }
334     }
335     dimensionResult = Dimension(result, defaultUnit);
336     return true;
337 }
338 
339 inline bool StringToCalcDimensionNG(
340     const std::string& value, CalcDimension& result, bool useVp = false,
341     DimensionUnit defaultUnit = DimensionUnit::PX)
342 {
343     if (value.find("calc") != std::string::npos) {
344         result = CalcDimension(value, DimensionUnit::CALC);
345         return true;
346     } else {
347         return StringToDimensionWithUnitNG(value, result, useVp ? DimensionUnit::VP : defaultUnit);
348     }
349 }
350 
StringToDegree(const std::string & value)351 inline double StringToDegree(const std::string& value)
352 {
353     // https://developer.mozilla.org/zh-CN/docs/Web/CSS/angle
354     constexpr static double DEGREES = 360.0;
355     constexpr static double GRADIANS = 400.0;
356     constexpr static double RADIUS = 2 * M_PI;
357 
358     errno = 0;
359     char* pEnd = nullptr;
360     double result = std::strtod(value.c_str(), &pEnd);
361     if (pEnd == value.c_str() || errno == ERANGE) {
362         return 0.0;
363     } else if (pEnd) {
364         if ((std::strcmp(pEnd, "deg")) == 0) {
365             return result;
366         } else if (std::strcmp(pEnd, "grad") == 0) {
367             return result / GRADIANS * DEGREES;
368         } else if (std::strcmp(pEnd, "rad") == 0) {
369             return result / RADIUS * DEGREES;
370         } else if (std::strcmp(pEnd, "turn") == 0) {
371             return result * DEGREES;
372         }
373     }
374     return StringToDouble(value);
375 }
376 
377 template<class T>
StringSplitter(const std::string & source,char delimiter,T (* func)(const std::string &),std::vector<T> & out)378 inline void StringSplitter(
379     const std::string& source, char delimiter, T (*func)(const std::string&), std::vector<T>& out)
380 {
381     out.erase(out.begin(), out.end());
382 
383     if (source.empty()) {
384         return;
385     }
386 
387     std::size_t startIndex = 0;
388     for (std::size_t index = 0; index < source.size(); index++) {
389         if (source[index] != delimiter) {
390             continue;
391         }
392 
393         if (index > startIndex) {
394             out.emplace_back(func(source.substr(startIndex, index - startIndex)));
395         }
396         startIndex = index + 1;
397     }
398 
399     if (startIndex < source.size()) {
400         out.emplace_back(func(source.substr(startIndex)));
401     }
402 }
403 
StringSplitter(const std::string & source,char delimiter,std::vector<std::string> & out)404 inline void StringSplitter(const std::string& source, char delimiter, std::vector<std::string>& out)
405 {
406     using Func = std::string (*)(const std::string&);
407     Func func = [](const std::string& value) { return value; };
408     StringSplitter(source, delimiter, func, out);
409 }
410 
StringSplitter(const std::string & source,char delimiter,std::vector<double> & out)411 inline void StringSplitter(const std::string& source, char delimiter, std::vector<double>& out)
412 {
413     using Func = double (*)(const std::string&);
414     Func func = [](const std::string& value) { return StringToDouble(value); };
415     StringSplitter(source, delimiter, func, out);
416 }
417 
StringSplitter(const std::string & source,char delimiter,std::vector<float> & out)418 inline void StringSplitter(const std::string& source, char delimiter, std::vector<float>& out)
419 {
420     using Func = float (*)(const std::string&);
421     Func func = [](const std::string& value) { return StringToFloat(value); };
422     StringSplitter(source, delimiter, func, out);
423 }
424 
StringSplitter(const std::string & source,char delimiter,std::vector<int> & out)425 inline void StringSplitter(const std::string& source, char delimiter, std::vector<int>& out)
426 {
427     using Func = int32_t (*)(const std::string&);
428     Func func = [](const std::string& value) { return StringToInt(value); };
429     StringSplitter(source, delimiter, func, out);
430 }
431 
StringSplitter(const std::string & source,char delimiter,std::vector<Dimension> & out)432 inline void StringSplitter(const std::string& source, char delimiter, std::vector<Dimension>& out)
433 {
434     using Func = Dimension (*)(const std::string&);
435     Func func = [](const std::string& value) { return StringToDimension(value); };
436     StringSplitter(source, delimiter, func, out);
437 }
438 
439 inline std::string DoubleToString(double value, int32_t precision = 2)
440 {
441     std::ostringstream result;
442     result.precision(precision);
443     if (NearEqual(value, Infinity<double>())) {
444         result << "Infinity";
445     } else {
446         result << std::fixed << value;
447     }
448     return result.str();
449 }
450 
DeleteAllMark(std::string & str,const char mark)451 inline void DeleteAllMark(std::string& str, const char mark)
452 {
453     str.erase(std::remove(str.begin(), str.end(), mark), str.end());
454 }
455 
456 inline std::string TrimStr(const std::string& str, char cTrim = ' ')
457 {
458     auto firstPos = str.find_first_not_of(cTrim);
459     if (firstPos == std::string::npos) {
460         return str;
461     }
462     auto endPos = str.find_last_not_of(cTrim);
463     return str.substr(firstPos, endPos - firstPos + 1);
464 }
465 
466 inline void TrimStrLeadingAndTrailing(std::string& str, char cTrim = ' ')
467 {
468     auto firstIndexNotOfSpace = str.find_first_not_of(" ");
469     if (firstIndexNotOfSpace == std::string::npos) {
470         str = "";
471         return;
472     }
473     str.erase(0, firstIndexNotOfSpace);
474     auto lastIndexNotOfSpace = str.find_last_not_of(" ");
475     if (lastIndexNotOfSpace == std::string::npos) {
476         str = "";
477         return;
478     }
479     str.erase(lastIndexNotOfSpace + 1);
480 }
481 
482 inline void SplitStr(
483     const std::string& str, const std::string& sep, std::vector<std::string>& out, bool needTrim = true)
484 {
485     out.erase(out.begin(), out.end());
486 
487     if (str.empty() || sep.empty()) {
488         return;
489     }
490 
491     std::string strPart;
492     std::string::size_type startPos = 0;
493     std::string::size_type pos = str.find_first_of(sep, startPos);
494     while (pos != std::string::npos) {
495         if (pos > startPos) {
496             strPart = needTrim ? TrimStr(str.substr(startPos, pos - startPos)) : str.substr(startPos, pos - startPos);
497             out.emplace_back(std::move(strPart));
498         }
499         startPos = pos + sep.size();
500         pos = str.find_first_of(sep, startPos);
501     }
502 
503     if (startPos < str.size()) {
504         strPart = needTrim ? TrimStr(str.substr(startPos)) : str.substr(startPos);
505         out.emplace_back(std::move(strPart));
506     }
507 }
508 
509 inline void SplitStr(const std::string& str, const std::string& sep, std::vector<Dimension>& out, bool needTrim = true)
510 {
511     out.erase(out.begin(), out.end());
512     if (str.empty() || sep.empty()) {
513         return;
514     }
515     std::string strPart;
516     std::string::size_type startPos = 0;
517     std::string::size_type pos = str.find_first_of(sep, startPos);
518     while (pos != std::string::npos) {
519         if (pos > startPos) {
520             strPart = needTrim ? TrimStr(str.substr(startPos, pos - startPos)) : str.substr(startPos, pos - startPos);
521             if (!strPart.empty()) {
522                 out.emplace_back(StringToDimension(std::move(strPart)));
523             }
524         }
525         startPos = pos + sep.size();
526         pos = str.find_first_of(sep, startPos);
527     }
528     if (startPos < str.size()) {
529         strPart = needTrim ? TrimStr(str.substr(startPos)) : str.substr(startPos);
530         if (!strPart.empty()) {
531             out.emplace_back(StringToDimension(std::move(strPart)));
532         }
533     }
534 }
535 
536 const std::string ACE_EXPORT FormatString(const char* fmt, ...);
537 
StartWith(const std::string & dst,const std::string & prefix)538 inline bool StartWith(const std::string& dst, const std::string& prefix)
539 {
540     return dst.compare(0, prefix.size(), prefix) == 0;
541 }
542 
StartWith(const std::string & str,const char * prefix,size_t prefixLen)543 inline bool StartWith(const std::string& str, const char* prefix, size_t prefixLen)
544 {
545     return ((str.length() >= prefixLen) && (str.compare(0, prefixLen, prefix) == 0));
546 }
547 
EndWith(const std::string & dst,const std::string & suffix)548 inline bool EndWith(const std::string& dst, const std::string& suffix)
549 {
550     return (dst.size() >= suffix.size()) && dst.compare(dst.size() - suffix.size(), suffix.size(), suffix) == 0;
551 }
552 
EndWith(const std::string & str,const char * suffix,size_t suffixLen)553 inline bool EndWith(const std::string& str, const char* suffix, size_t suffixLen)
554 {
555     size_t len = str.length();
556     return ((len >= suffixLen) && (str.compare(len - suffixLen, suffixLen, suffix) == 0));
557 }
558 
TransformStrCase(std::string & str,int32_t textCase)559 inline void TransformStrCase(std::string& str, int32_t textCase)
560 {
561     if (str.empty()) {
562         return;
563     }
564 
565     switch (textCase) {
566         case TEXT_CASE_LOWERCASE:
567             transform(str.begin(), str.end(), str.begin(), ::tolower);
568             break;
569         case TEXT_CASE_UPPERCASE:
570             transform(str.begin(), str.end(), str.begin(), ::toupper);
571             break;
572         default:
573             break;
574     }
575 }
576 
577 bool IsAscii(const std::string& str);
578 } // namespace OHOS::Ace::StringUtils
579 
580 #endif // FOUNDATION_ACE_FRAMEWORKS_BASE_UTILS_STRING_UTILS_H
581