openPMD-api
StringManip.hpp
1 /* Copyright 2017-2021 Fabian Koller, Franz Poeschel
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 <iterator>
26 #include <sstream>
27 #include <string>
28 #include <vector>
29 
30 namespace openPMD
31 {
32 namespace auxiliary
33 {
34  inline bool contains(std::string const &s, std::string const &infix)
35  {
36  return s.find(infix) != std::string::npos;
37  }
38 
39  inline bool contains(std::string const &s, char const infix)
40  {
41  return s.find(infix) != std::string::npos;
42  }
43 
44  inline bool starts_with(std::string const &s, std::string const &prefix)
45  {
46  return (s.size() >= prefix.size()) &&
47  (0 == s.compare(0, prefix.size(), prefix));
48  }
49 
50  inline bool starts_with(std::string const &s, char const prefix)
51  {
52  return !s.empty() && s[0] == prefix;
53  }
54 
55  inline bool ends_with(std::string const &s, std::string const &suffix)
56  {
57  return (s.size() >= suffix.size()) &&
58  (0 == s.compare(s.size() - suffix.size(), suffix.size(), suffix));
59  }
60 
61  inline bool ends_with(std::string const &s, char const suffix)
62  {
63  return !s.empty() && s.back() == suffix;
64  }
65 
66  inline std::string replace_first(
67  std::string s,
68  std::string const &target,
69  std::string const &replacement)
70  {
71  std::string::size_type pos = s.find(target);
72  if (pos == std::string::npos)
73  return s;
74  s.replace(pos, target.size(), replacement);
75  s.shrink_to_fit();
76 
77  return s;
78  }
79 
80  inline std::string replace_last(
81  std::string s,
82  std::string const &target,
83  std::string const &replacement)
84  {
85  std::string::size_type pos = s.rfind(target);
86  if (pos == std::string::npos)
87  return s;
88  s.replace(pos, target.size(), replacement);
89  s.shrink_to_fit();
90 
91  return s;
92  }
93 
94  inline std::string replace_all_nonrecursively(
95  std::string s,
96  std::string const &target,
97  std::string const &replacement)
98  {
99  std::string::size_type pos = 0;
100  auto tsize = target.size();
101  auto rsize = replacement.size();
102  while (true)
103  {
104  pos = s.find(target, pos);
105  if (pos == std::string::npos)
106  break;
107  s.replace(pos, tsize, replacement);
108  pos += rsize;
109  }
110  s.shrink_to_fit();
111  return s;
112  }
113 
114  inline std::string replace_all(
115  std::string s,
116  std::string const &target,
117  std::string const &replacement)
118  {
119  std::string::size_type pos = 0;
120  auto tsize = target.size();
121  assert(tsize > 0);
122  auto rsize = replacement.size();
123  while (true)
124  {
125  pos = s.find(target, pos);
126  if (pos == std::string::npos)
127  break;
128  s.replace(pos, tsize, replacement);
129  // Allow replacing recursively, but only if
130  // the next replaced substring overlaps with
131  // some parts of the original word.
132  // This avoids loops.
133  pos += rsize - std::min(tsize - 1, rsize);
134  }
135  s.shrink_to_fit();
136  return s;
137  }
138 
139  inline std::vector<std::string> split(
140  std::string const &s,
141  std::string const &delimiter,
142  bool includeDelimiter = false)
143  {
144  std::vector<std::string> ret;
145  std::string::size_type pos, lastPos = 0, length = s.size();
146  while (lastPos < length + 1)
147  {
148  pos = s.find_first_of(delimiter, lastPos);
149  if (pos == std::string::npos)
150  {
151  pos = length;
152  includeDelimiter = false;
153  }
154 
155  if (pos != lastPos)
156  ret.push_back(s.substr(
157  lastPos,
158  pos + (includeDelimiter ? delimiter.size() : 0) - lastPos));
159 
160  lastPos = pos + 1;
161  }
162 
163  return ret;
164  }
165 
166  inline std::string strip(std::string s, std::vector<char> to_remove)
167  {
168  for (auto const &c : to_remove)
169  s.erase(std::remove(s.begin(), s.end(), c), s.end());
170  s.shrink_to_fit();
171 
172  return s;
173  }
174 
175  template <typename F>
176  std::string trim(std::string const &s, F &&to_remove)
177  {
178  auto begin = s.begin();
179  for (; begin != s.end(); ++begin)
180  {
181  if (!to_remove(*begin))
182  {
183  break;
184  }
185  }
186  auto end = s.rbegin();
187  for (; end != s.rend(); ++end)
188  {
189  if (!to_remove(*end))
190  {
191  break;
192  }
193  }
194  return s.substr(begin - s.begin(), end.base() - begin);
195  }
196 
197  inline std::string
198  join(std::vector<std::string> const &vs, std::string const &delimiter)
199  {
200  switch (vs.size())
201  {
202  case 0:
203  return "";
204  case 1:
205  return vs[0];
206  default:
207  std::ostringstream ss;
208  std::copy(
209  vs.begin(),
210  vs.end() - 1,
211  std::ostream_iterator<std::string>(ss, delimiter.c_str()));
212  ss << *(vs.end() - 1);
213  return ss.str();
214  }
215  }
216 
223  inline std::string removeSlashes(std::string s)
224  {
225  if (auxiliary::starts_with(s, '/'))
226  {
227  s = auxiliary::replace_first(s, "/", "");
228  }
229  if (auxiliary::ends_with(s, '/'))
230  {
231  s = auxiliary::replace_last(s, "/", "");
232  }
233  return s;
234  }
235 
236 } // namespace auxiliary
237 } // namespace openPMD
std::string suffix(Format f)
Determine the default filename suffix for a given storage format.
Definition: Format.cpp:70
Public definitions of openPMD-api.
Definition: Date.cpp:28