String.h
1 /*
2  * Medical Image Registration ToolKit (MIRTK)
3  *
4  * Copyright 2013-2016 Imperial College London
5  * Copyright 2013-2016 Andreas Schuh
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 
20 #ifndef MIRTK_String_H
21 #define MIRTK_String_H
22 
23 #include "mirtk/CommonExport.h"
24 
25 #include <cctype>
26 #include <cstring>
27 #include <string>
28 #include <sstream>
29 #include <iomanip>
30 #include <limits>
31 
32 #include "mirtk/Array.h"
33 
34 
35 namespace mirtk {
36 
37 
38 // Basic C string functions
39 using ::isalnum;
40 using ::isdigit;
41 using ::islower;
42 using ::isupper;
43 using ::tolower;
44 using ::toupper;
45 using ::strstr;
46 using ::strcmp;
47 using ::strncmp;
48 
49 // Import C++ library type into mirtk namespace
50 using std::string;
51 
52 
53 // =============================================================================
54 // String comparison
55 // =============================================================================
56 
57 /// Case insensitive string comparison
58 inline bool iequal(char const *a, char const *b)
59 {
60  while (*a && *b) {
61  if (tolower(*a) != tolower(*b)) return false;
62  ++a, ++b;
63  }
64  return !(*a || *b);
65 }
66 
67 /// Case insensitive string comparison
68 inline bool iequal(const string &a, char const *b)
69 {
70  return iequal(a.c_str(), b);
71 }
72 
73 /// Case insensitive string comparison
74 inline bool iequal(const char *a, const string &b)
75 {
76  return iequal(a, b.c_str());
77 }
78 
79 /// Case insensitive string comparison
80 inline bool iequal(const string &a, const string &b)
81 {
82  return iequal(a.c_str(), b.c_str());
83 }
84 
85 // =============================================================================
86 // Custom string/stream functions
87 // =============================================================================
88 
89 /// General routine to read float from a file stream
90 MIRTK_Common_DEPRECATED int ReadInt(std::ifstream &);
91 
92 /// General routine to read float from a file stream
93 MIRTK_Common_DEPRECATED float ReadFloat(std::ifstream &);
94 
95 /// General routine to read list of char (string) from a file stream
96 MIRTK_Common_DEPRECATED char *ReadString(std::ifstream &);
97 
98 /// Convert string to numeric value
99 template <typename T>
100 bool FromString(const char *str, T &value)
101 {
102  if (str == NULL || str[0] == '\0') return false;
103  std::istringstream is(str);
104  return !(is >> value).fail() && is.eof();
105 }
106 
107 /// Convert string to numeric value
108 template <typename T>
109 bool FromString(const string &s, T &value)
110 {
111  return FromString(s.c_str(), value);
112 }
113 
114 /// Convert string to boolean value
115 template <>
116 inline bool FromString(const char *str, bool &value)
117 {
118  if (strcmp(str, "yes") == 0 || strcmp(str, "Yes") == 0 || strcmp(str, "YES") == 0) {
119  value = true;
120  return true;
121  } else if (strcmp(str, "no") == 0 || strcmp(str, "No") == 0 || strcmp(str, "NO") == 0) {
122  value = false;
123  return true;
124  } else if (strcmp(str, "true") == 0 || strcmp(str, "True") == 0 || strcmp(str, "TRUE") == 0) {
125  value = true;
126  return true;
127  } else if (strcmp(str, "false") == 0 || strcmp(str, "False") == 0 || strcmp(str, "FALSE") == 0) {
128  value = false;
129  return true;
130  } else if (strcmp(str, "on") == 0 || strcmp(str, "On") == 0 || strcmp(str, "ON") == 0) {
131  value = true;
132  return true;
133  } else if (strcmp(str, "off") == 0 || strcmp(str, "Off") == 0 || strcmp(str, "OFF") == 0) {
134  value = false;
135  return true;
136  } else {
137  std::istringstream is(str);
138  return !(is >> value).fail() && is.eof();
139  }
140 }
141 
142 /// Convert string to float value
143 template <>
144 inline bool FromString(const char *str, float &value)
145 {
146  if (strcmp(str, "nan") == 0 || strcmp(str, "NaN") == 0) {
147  value = std::numeric_limits<float>::quiet_NaN();
148  return true;
149  } else if (strcmp(str, "-inf") == 0 || strcmp(str, "-Inf") == 0) {
150  value = -std::numeric_limits<float>::infinity();
151  return true;
152  } else if (strcmp(str, "+inf") == 0 || strcmp(str, "inf") == 0 || strcmp(str, "+Inf") == 0 || strcmp(str, "Inf") == 0) {
153  value = +std::numeric_limits<float>::infinity();
154  return true;
155  } else {
156  std::istringstream is(str);
157  return !(is >> value).fail() && is.eof();
158  }
159 }
160 
161 /// Convert string to double value
162 template <>
163 inline bool FromString(const char *str, double &value)
164 {
165  if (strcmp(str, "nan") == 0 || strcmp(str, "NaN") == 0) {
166  value = std::numeric_limits<double>::quiet_NaN();
167  return true;
168  } else if (strcmp(str, "-inf") == 0 || strcmp(str, "-Inf") == 0) {
169  value = -std::numeric_limits<double>::infinity();
170  return true;
171  } else if (strcmp(str, "+inf") == 0 || strcmp(str, "inf") == 0 || strcmp(str, "+Inf") == 0 || strcmp(str, "Inf") == 0) {
172  value = +std::numeric_limits<double>::infinity();
173  return true;
174  } else {
175  std::istringstream is(str);
176  return !(is >> value).fail() && is.eof();
177  }
178 }
179 
180 /// Check if given string represents a value of the specified template type
181 template <typename T> bool IsValueOfType(const char *str)
182 {
183  T value;
184  return FromString(str, value);
185 }
186 
187 /// Check if given string is a (floating point) number
188 inline bool IsNumber(const char *str)
189 {
190  return IsValueOfType<double>(str);
191 }
192 
193 /// Check if given string is an integer value
194 inline bool IsInteger(const char *str)
195 {
196  return IsValueOfType<int>(str);
197 }
198 
199 /// Convert numeric value to string
200 template <typename T>
201 string ToString(const T &value, int w = 0, char c = ' ', bool left = false)
202 {
203  std::ostringstream os;
204  os.fill(c);
205  if (left) os << std::left;
206  else os << std::right;
207  os << std::setw(w) << value;
208  return os.str();
209 }
210 
211 /// Convert boolean value to string
212 template <>
213 inline string ToString(const bool &value, int w, char c, bool left)
214 {
215  std::ostringstream os;
216  os.fill(c);
217  if (left) os << std::left;
218  else os << std::right;
219  os << std::setw(w) << (value ? "Yes" : "No");
220  return os.str();
221 }
222 
223 /// Write "<name> = <value>" configuration entry to output stream
224 inline void PrintParameter(std::ostream &os, const char *name, const char *value)
225 {
226  const std::streamsize w = os.width(40);
227  os << std::left << name << std::setw(0) << " = " << value << "\n";
228  os.width(w);
229 }
230 
231 /// Write "<name> = <value>" configuration entry to output stream
232 inline void PrintParameter(std::ostream &os, const char *name, const string &value)
233 {
234  PrintParameter(os, name, value.c_str());
235 }
236 
237 /// Write "<name> = <value>" configuration entry to output stream
238 inline void PrintParameter(std::ostream &os, const string &name, const string &value)
239 {
240  PrintParameter(os, name.c_str(), value.c_str());
241 }
242 
243 /// Write "<name> = <value>" configuration entry to output stream
244 template <class TValue>
245 inline void PrintParameter(std::ostream &os, const char *name, const TValue &value)
246 {
247  PrintParameter(os, name, ToString(value));
248 }
249 
250 /// Write "<name> = <value>" configuration entry to output stream
251 template <class TValue>
252 inline void PrintParameter(std::ostream &os, const string &name, const TValue &value)
253 {
254  PrintParameter(os, name, ToString(value));
255 }
256 
257 /// Print single argument to output stream
258 template <typename T>
259 std::ostream &Print(std::ostream &os, T value)
260 {
261  os << ToString(value);
262  return os;
263 }
264 
265 /// Print any number of arguments to output stream, i.e.,
266 /// concatenating the string representations of the arguments
267 template <typename T, typename... Args>
268 std::ostream &Print(std::ostream &os, T value, Args... args)
269 {
270  os << ToString(value);
271  return Print(os, args...);
272 }
273 
274 /// Convert string to lowercase letters
275 string ToLower(const string &);
276 
277 /// Convert string to uppercase letters
278 string ToUpper(const string &);
279 
280 /// Trim leading and trailing (whitespace) characters from string
281 ///
282 /// \param[in] str Input string.
283 /// \param[in] what Set of characters to remove from start and end of string.
284 ///
285 /// \returns String with leading and trailing (whitespace) characters removed.
286 string Trim(const string &str, const string &what = " \t\r\n");
287 
288 /// Remove (whitespace) characters from string
289 ///
290 /// \param[in] str Input string.
291 /// \param[in] what Set of characters to remove from string.
292 ///
293 /// \returns String with leading and trailing (whitespace) characters removed.
294 string TrimAll(const string &str, const string &what = " \t\r\n");
295 
296 /// Split string into parts separated by specified delimiting sequence of characters
297 ///
298 /// @param s String to be split.
299 /// @param d Delimiting sequence of characters.
300 /// @param n Maximum number of parts. If zero, all parts are returned,
301 /// if negative, the last n parts are returned, and if positive,
302 /// the first n parts are returned.
303 /// @param e Discard empty strings.
304 /// @param q Do not split quoted parts. Double quotes within quotes
305 /// have to be escaped with a preceding backslash character.
306 ///
307 /// @returns Parts of the string.
308 Array<string> Split(string s, const char *d, int n = 0, bool e = false, bool q = false);
309 
310 /// Split string into parts separated by specified delimiting character
311 ///
312 /// @param s String to be split.
313 /// @param d Delimiting character.
314 /// @param n Maximum number of parts. If zero, all parts are returned,
315 /// if negative, the last n parts are returned, and if positive,
316 /// the first n parts are returned.
317 /// @param e Discard empty strings.
318 /// @param q Do not split quoted parts. Double quotes within quotes
319 /// have to be escaped with a preceding backslash character.
320 ///
321 /// @returns Parts of the string.
322 Array<string> Split(string s, char d, int n = 0, bool e = false, bool q = false);
323 
324 /// Convert (upper) camel case string to space separated string
325 ///
326 /// \param[in] s Camel case string.
327 ///
328 /// \return String starting with uppercase letter followed by lowercase letters
329 /// only and a space character before each uppercase letter in the
330 /// camel case string.
331 string CamelCaseToPrettyParameterName(const string &s);
332 
333 /// Convert units specification to standard lowercase string
334 ///
335 /// For example, this function returns "vox" for any units specification allowed
336 /// for voxel units including "voxel" and "VOxELS". Same for other units for
337 /// which alternative units specifications are allowed. Removes enclosing
338 /// brackets from units string if present, e.g., returns "mm" when the input
339 /// string is "[mm]".
340 ///
341 /// \param[in] str Units specification string.
342 ///
343 /// \returns Standard units specification in all lowercase.
344 string StandardUnits(const string &str);
345 
346 /// Splits a parameter name string such as "Resolution [mm]" into prefix and units
347 ///
348 /// \param[in] str Parameter name string with optional units specification.
349 /// \param[out] name Name of parameter without units specification.
350 /// \param[in] dflt Default units if none specified.
351 ///
352 /// \returns Standard units string or \p dflt string if units specification missing.
353 string ParameterUnits(const string &str, string *name = nullptr, const char *dflt = "");
354 
355 /// Splits a parameter value string such as "1 mm", "1 [mm]", "1 2 3 mm", "foo [rel]"
356 ///
357 /// \note When the parameter value is not numeric, the units specification must
358 /// be enclosed in square brackets ([]) and separated by at least one white
359 /// space character from the parameter value(s).
360 ///
361 /// \param[in] str Numeric parameter value string with optional units specification.
362 /// \param[out] value Value(s) of parameter without units specification.
363 /// \param[in] dflt Default units if none specified.
364 ///
365 /// \returns Standard units string or \p dflt string if units specification missing.
366 string ValueUnits(const string &str, string *value = nullptr, const char *dflt = "");
367 
368 
369 } // namespace mirtk
370 
371 #endif // MIRTK_String_H
bool IsValueOfType(const char *str)
Check if given string represents a value of the specified template type.
Definition: String.h:181
string Trim(const string &str, const string &what=" \\)
string StandardUnits(const string &str)
MIRTK_Common_DEPRECATED float ReadFloat(std::ifstream &)
General routine to read float from a file stream.
MIRTK_Common_DEPRECATED int ReadInt(std::ifstream &)
General routine to read float from a file stream.
string TrimAll(const string &str, const string &what=" \\)
bool iequal(char const *a, char const *b)
Case insensitive string comparison.
Definition: String.h:58
void PrintParameter(std::ostream &os, const char *name, const char *value)
Write "<name> = <value>" configuration entry to output stream.
Definition: String.h:224
string ParameterUnits(const string &str, string *name=nullptr, const char *dflt="")
bool IsInteger(const char *str)
Check if given string is an integer value.
Definition: String.h:194
string ToLower(const string &)
Convert string to lowercase letters.
Definition: IOConfig.h:41
string ValueUnits(const string &str, string *value=nullptr, const char *dflt="")
MIRTK_Common_DEPRECATED char * ReadString(std::ifstream &)
General routine to read list of char (string) from a file stream.
Array< string > Split(string s, const char *d, int n=0, bool e=false, bool q=false)
string ToString(const EnergyMeasure &value, int w, char c, bool left)
Convert energy measure enumeration value to string.
bool FromString(const char *str, EnergyMeasure &value)
Convert energy measure string to enumeration value.
bool IsNumber(const char *str)
Check if given string is a (floating point) number.
Definition: String.h:188
string CamelCaseToPrettyParameterName(const string &s)
std::ostream & Print(std::ostream &os, T value)
Print single argument to output stream.
Definition: String.h:259
string ToUpper(const string &)
Convert string to uppercase letters.