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