1 /*
2 * Copyright (c) 2024 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 CORE_UTIL_STRING_UTIL_H
17 #define CORE_UTIL_STRING_UTIL_H
18
19 #include <algorithm>
20 #include <cctype>
21 #include <cstddef>
22 #include <iterator>
23
24 #include <base/containers/iterator.h>
25 #include <base/containers/string.h>
26 #include <base/containers/string_view.h>
27 #include <base/containers/vector.h>
28 #include <core/log.h>
29 #include <core/namespace.h>
30
CORE_BEGIN_NAMESPACE()31 CORE_BEGIN_NAMESPACE()
32 namespace StringUtil {
33 template<class T, size_t N>
34 constexpr size_t MaxStringLengthFromArray(T (&)[N])
35 {
36 return N - 1u;
37 }
38
39 inline void CopyStringToArray(const BASE_NS::string_view source, char* target, size_t maxLength)
40 {
41 if (source.size() > maxLength) {
42 CORE_LOG_W("CopyStringToArray: string (%zu) longer than %zu", source.size(), maxLength);
43 }
44 size_t const length = source.copy(target, maxLength);
45 target[length] = '\0';
46 }
47
48 inline bool NotSpace(unsigned char ch)
49 {
50 return !std::isspace(static_cast<int>(ch));
51 }
52
53 // trim from start (in place)
54 inline void LTrim(BASE_NS::string_view& string)
55 {
56 auto const count = size_t(std::find_if(string.begin(), string.end(), NotSpace) - string.begin());
57 string.remove_prefix(count);
58 }
59
60 // trim from end (in place)
61 inline void RTrim(BASE_NS::string_view& string)
62 {
63 auto const count =
64 size_t(std::distance(std::find_if(string.rbegin(), string.rend(), NotSpace).base(), string.end()));
65 string.remove_suffix(count);
66 }
67
68 // trim from both ends (in place)
69 inline size_t Trim(BASE_NS::string_view& string)
70 {
71 RTrim(string);
72 LTrim(string);
73 return string.length();
74 }
75
76 inline BASE_NS::vector<BASE_NS::string_view> Split(
77 const BASE_NS::string_view string, const BASE_NS::string_view delims = "|")
78 {
79 BASE_NS::vector<BASE_NS::string_view> output;
80 auto left = string;
81
82 while (!left.empty()) {
83 auto const pos = left.find_first_of(delims);
84
85 auto found = left.substr(0, pos);
86 if (Trim(found) > 0) {
87 output.push_back(found);
88 }
89 if (pos != BASE_NS::string_view::npos) {
90 left.remove_prefix(pos + 1);
91 } else {
92 break;
93 }
94 }
95
96 return output;
97 }
98
99 // find and replace first instance of "find" with "replace" in "source"
100 inline bool FindAndReplaceOne(
101 BASE_NS::string& source, const BASE_NS::string_view find, const BASE_NS::string_view replace)
102 {
103 const auto p = source.find(find);
104 if (p != BASE_NS::string::npos) {
105 source.replace(source.cbegin() + static_cast<BASE_NS::string::difference_type>(p),
106 source.cbegin() + static_cast<BASE_NS::string::difference_type>(p + find.length()), replace);
107 }
108 return (p != BASE_NS::string::npos);
109 }
110 // find and replace all instances of "find" with "replace" in "source"
111 inline void FindAndReplaceAll(
112 BASE_NS::string& source, const BASE_NS::string_view find, const BASE_NS::string_view replace)
113 {
114 while (FindAndReplaceOne(source, find, replace))
115 ;
116 }
117 } // namespace StringUtil
118 CORE_END_NAMESPACE()
119
120 #endif // CORE_UTIL_STRING_UTIL_H
121