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