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 <cctype> // std::tolower
26 #include <iterator>
27 #include <sstream>
28 #include <string>
29 #include <vector>
30 
31 namespace openPMD
32 {
33 namespace 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 } // namespace auxiliary
246 } // 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