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