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