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