openPMD-api
 
Loading...
Searching...
No Matches
StringManip.hpp
1/* Copyright 2017-2025 Fabian Koller, Franz Poeschel, Axel Huebl, Junmin Gu
2 *
3 * This file is part of openPMD-api.
4 *
5 * openPMD-api is free software: you can redistribute it and/or modify
6 * it under the terms of of either the GNU General Public License or
7 * the GNU Lesser General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * openPMD-api is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License and the GNU Lesser General Public License
15 * for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * and the GNU Lesser General Public License along with openPMD-api.
19 * If not, see <http://www.gnu.org/licenses/>.
20 */
21#pragma once
22
23#include <algorithm>
24#include <cassert>
25#include <cctype> // std::tolower
26#include <iterator>
27#include <sstream>
28#include <string>
29#include <vector>
30
31namespace openPMD
32{
33namespace auxiliary
34{
35 inline bool contains(std::string const &s, std::string const &infix)
36 {
37 return s.find(infix) != std::string::npos;
38 }
39
40 inline bool contains(std::string const &s, char const infix)
41 {
42 return s.find(infix) != std::string::npos;
43 }
44
45 inline bool starts_with(std::string const &s, std::string const &prefix)
46 {
47 return (s.size() >= prefix.size()) &&
48 (0 == s.compare(0, prefix.size(), prefix));
49 }
50
51 inline bool starts_with(std::string const &s, char const prefix)
52 {
53 return !s.empty() && s[0] == prefix;
54 }
55
56 inline bool ends_with(std::string const &s, std::string const &suffix)
57 {
58 return (s.size() >= suffix.size()) &&
59 (0 == s.compare(s.size() - suffix.size(), suffix.size(), suffix));
60 }
61
62 inline bool ends_with(std::string const &s, char const suffix)
63 {
64 return !s.empty() && s.back() == suffix;
65 }
66
67 inline std::string replace_first(
68 std::string s,
69 std::string const &target,
70 std::string const &replacement)
71 {
72 std::string::size_type pos = s.find(target);
73 if (pos == std::string::npos)
74 return s;
75 s.replace(pos, target.size(), replacement);
76 s.shrink_to_fit();
77
78 return s;
79 }
80
81 inline std::string replace_last(
82 std::string s,
83 std::string const &target,
84 std::string const &replacement)
85 {
86 std::string::size_type pos = s.rfind(target);
87 if (pos == std::string::npos)
88 return s;
89 s.replace(pos, target.size(), replacement);
90 s.shrink_to_fit();
91
92 return s;
93 }
94
95 inline std::string replace_all_nonrecursively(
96 std::string s,
97 std::string const &target,
98 std::string const &replacement)
99 {
100 std::string::size_type pos = 0;
101 auto tsize = target.size();
102 auto rsize = replacement.size();
103 while (true)
104 {
105 pos = s.find(target, pos);
106 if (pos == std::string::npos)
107 break;
108 s.replace(pos, tsize, replacement);
109 pos += rsize;
110 }
111 s.shrink_to_fit();
112 return s;
113 }
114
115 inline std::string replace_all(
116 std::string s,
117 std::string const &target,
118 std::string const &replacement)
119 {
120 std::string::size_type pos = 0;
121 auto tsize = target.size();
122 assert(tsize > 0);
123 auto rsize = replacement.size();
124 while (true)
125 {
126 pos = s.find(target, pos);
127 if (pos == std::string::npos)
128 break;
129 s.replace(pos, tsize, replacement);
130 // Allow replacing recursively, but only if
131 // the next replaced substring overlaps with
132 // some parts of the original word.
133 // This avoids loops.
134 pos += rsize - std::min(tsize - 1, rsize);
135 }
136 s.shrink_to_fit();
137 return s;
138 }
139
140 inline std::vector<std::string> split(
141 std::string const &s,
142 std::string const &delimiter,
143 bool includeDelimiter = false)
144 {
145 std::vector<std::string> ret;
146 std::string::size_type pos, lastPos = 0, length = s.size();
147 while (lastPos < length + 1)
148 {
149 pos = s.find_first_of(delimiter, lastPos);
150 if (pos == std::string::npos)
151 {
152 pos = length;
153 includeDelimiter = false;
154 }
155
156 if (pos != lastPos)
157 ret.push_back(s.substr(
158 lastPos,
159 pos + (includeDelimiter ? delimiter.size() : 0) - lastPos));
160
161 lastPos = pos + 1;
162 }
163
164 return ret;
165 }
166
167 inline std::string strip(std::string s, std::vector<char> to_remove)
168 {
169 for (auto const &c : to_remove)
170 s.erase(std::remove(s.begin(), s.end(), c), s.end());
171 s.shrink_to_fit();
172
173 return s;
174 }
175
176 template <typename F>
177 std::string trim(std::string const &s, F &&to_remove)
178 {
179 auto begin = s.begin();
180 for (; begin != s.end(); ++begin)
181 {
182 if (!to_remove(*begin))
183 {
184 break;
185 }
186 }
187 auto end = s.rbegin();
188 for (; end != s.rend(); ++end)
189 {
190 if (!to_remove(*end))
191 {
192 break;
193 }
194 }
195 return s.substr(begin - s.begin(), end.base() - begin);
196 }
197
198 inline std::string
199 join(std::vector<std::string> const &vs, std::string const &delimiter)
200 {
201 switch (vs.size())
202 {
203 case 0:
204 return "";
205 case 1:
206 return vs[0];
207 default:
208 std::ostringstream ss;
209 std::copy(
210 vs.begin(),
211 vs.end() - 1,
212 std::ostream_iterator<std::string>(ss, delimiter.c_str()));
213 ss << *(vs.end() - 1);
214 return ss.str();
215 }
216 }
217
224 inline std::string removeSlashes(std::string s)
225 {
226 if (auxiliary::starts_with(s, '/'))
227 {
228 s = auxiliary::replace_first(s, "/", "");
229 }
230 if (auxiliary::ends_with(s, '/'))
231 {
232 s = auxiliary::replace_last(s, "/", "");
233 }
234 return s;
235 }
236
237 template <typename S>
238 S &&lowerCase(S &&s)
239 {
240 std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) {
241 return std::tolower(c);
242 });
243 return std::forward<S>(s);
244 }
245
246 template <typename Stream, typename Vec>
247 auto write_vec_to_stream(Stream &&s, Vec const &vec) -> Stream &&
248 {
249 if (vec.empty())
250 {
251 s << "[]";
252 }
253 else
254 {
255 s << '[';
256 auto it = vec.begin();
257 s << *it++;
258 auto end = vec.end();
259 for (; it != end; ++it)
260 {
261 s << ", " << *it;
262 }
263 s << ']';
264 }
265 return std::forward<Stream>(s);
266 }
267
268 template <typename Vec>
269 auto vec_as_string(Vec const &vec) -> std::string
270 {
271 if (vec.empty())
272 {
273 return "[]";
274 }
275 else
276 {
277 return write_vec_to_stream(std::stringstream(), vec).str();
278 }
279 }
280} // namespace auxiliary
281} // namespace openPMD
Public definitions of openPMD-api.
Definition Date.cpp:29
std::string suffix(Format f)
Determine the default filename suffix for a given storage format.
Definition Format.cpp:55