Audio Processing Framework (APF) version 0.5.0
stringtools.h
Go to the documentation of this file.
1/******************************************************************************
2 Copyright (c) 2012-2016 Institut für Nachrichtentechnik, Universität Rostock
3 Copyright (c) 2006-2012 Quality & Usability Lab
4 Deutsche Telekom Laboratories, TU Berlin
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 THE SOFTWARE.
23*******************************************************************************/
24
25// https://AudioProcessingFramework.github.io/
26
29
30#ifndef APF_STRINGTOOLS_H
31#define APF_STRINGTOOLS_H
32
33#include <string>
34#include <sstream>
35#include <stdexcept> // for std::invalid_argument
36
37namespace apf
38{
40namespace str
41{
42
51template<typename T>
52std::string A2S(const T& input)
53{
54 std::ostringstream converter;
55 converter << std::boolalpha << input;
56 return converter.str();
57}
58
68template<typename out_T>
69inline bool convert(std::istream& input, out_T& output)
70{
71 auto result = out_T();
72
73 input >> result;
74 if (input.fail()) return false;
75
76 input >> std::ws;
77 if (!input.eof()) return false;
78
79 output = result;
80 return true;
81}
82
90inline bool convert(std::istream& input, bool& output)
91{
92 bool result;
93 // first try: if input == "1" or "0":
94 input >> result;
95 if (input.fail())
96 {
97 input.clear(); // clear error flags
98 input.seekg(0); // go back to the beginning of the stream
99 // second try: if input == "true" or "false":
100 input >> std::boolalpha >> result;
101 }
102 if (input.fail()) return false;
103
104 input >> std::ws;
105 if (!input.eof()) return false;
106
107 output = result;
108 return true;
109}
110
121template<typename out_T>
122bool S2A(const std::string& input, out_T& output)
123{
124 std::istringstream converter(input);
125 return convert(converter, output);
126}
127
132inline bool S2A(const std::string& input, std::string& output)
133{
134 output = input;
135 return true;
136}
137
151template<typename out_T>
152out_T S2RV(const std::string& input, out_T def)
153{
154 S2A(input, def); // ignore return value
155 return def;
156}
157
162inline std::string S2RV(const std::string& input, const char* def)
163{
164 std::string temp(def);
165 S2A(input, temp); // ignore return value
166 return temp;
167}
168
177template<typename out_T, typename in_T>
178out_T S2RV(const in_T& input)
179{
180 auto result = out_T();
181 if (!S2A(input, result))
182 {
183 throw std::invalid_argument(
184 "S2RV(): Couldn't convert \"" + S2RV(input, std::string()) + "\"!");
185 }
186 return result;
187}
188
204template<typename char_T, typename traits>
205std::basic_ios<char_T, traits>&
206clear_iostate_except_eof(std::basic_ios<char_T, traits>& stream)
207{
208 stream.clear(stream.rdstate() & std::ios_base::eofbit);
209 return stream;
210}
211
226template<int digits, typename char_T, typename traits, typename out_T>
227std::basic_istream<char_T, traits>&
228convert_chars(std::basic_istream<char_T, traits>& input, out_T& output)
229{
230 static_assert(digits > 0, "'digits' must be at least 1!");
231
232 // if an error bit is set on the input, just return without doing anything:
233 if (input.fail()) return input;
234 // skip whitespace if std::skipws is set
235 if (input.flags() & std::ios_base::skipws) input >> std::ws;
236
237 char_T ch[digits];
238 if (!input.read(ch, digits)) return input; // error bits are set!
239
240 out_T factor = 1, result = 0;
241 for (int i = digits - 1; i >= 0; --i)
242 {
243 // only numbers are allowed:
244 if (ch[i] < input.widen('0') || ch[i] > input.widen('9'))
245 {
246 input.setstate(std::ios_base::failbit);
247 return input; // error bits are set!
248 }
249 // character type is implicitly cast to out_T
250 result += (ch[i] - '0') * factor;
251 factor *= 10;
252 }
253 output = result;
254 return input;
255}
256
268template<typename char_T, typename traits>
269std::basic_istream<char_T, traits>&
270remove_char(std::basic_istream<char_T, traits>& input, const char_T character)
271{
272 // if an error bit is set on the input, just return without doing anything:
273 if (input.fail()) return input;
274 // skip whitespace if std::skipws is set
275 if (input.flags() & std::ios_base::skipws) input >> std::ws;
276
277 char_T ch;
278 if (input.get(ch) && (ch != character))
279 {
280 input.setstate(std::ios_base::failbit);
281 }
282 return input;
283}
284
302template<typename char_T, typename traits>
303std::basic_istream<char_T, traits>&
304remove_colon(std::basic_istream<char_T, traits>& input)
305{
306 remove_char(input, input.widen(':'));
307 return input;
308}
309
328template<template<typename, typename, typename> class in_T,
329 typename char_T, typename traits, typename Allocator, typename out_T>
330bool string2time(const in_T<char_T, traits, Allocator>& input, out_T& output)
331{
332 // first of all, check if there are 0, 1 or 2 colons:
333 char colons = 0;
334 for (size_t found = 0
335 ; (found = input.find(':', found + 1)) != std::string::npos
336 ; ++colons) {}
337
338 std::basic_istringstream<char_T> iss(input);
339 out_T seconds = 0; // initialisation is needed for the case (colons == 1)!
340
341 if (colons == 0)
342 {
343 // no colons, but maybe suffixes like "s", "min", "h" or "ms"
344 out_T number;
345 iss >> number;
346 if (iss.fail()) return false;
347
348 iss >> std::ws >> clear_iostate_except_eof;
349 if (iss.eof()) // that's everything, no suffixes!
350 {
351 seconds = number;
352 }
353 else // still something left ...
354 {
355 auto the_rest = std::basic_string<char_T>();
356
357 iss >> the_rest;
358 if (iss.fail()) return false;
359
360 iss >> std::ws >> clear_iostate_except_eof;
361 if (!iss.eof()) return false;
362
363 // now check for possible suffixes:
364 if (the_rest == "h") seconds = number * 60 * 60;
365 else if (the_rest == "min") seconds = number * 60;
366 else if (the_rest == "s") seconds = number;
367 else if (the_rest == "ms")
368 {
369 // check if milliseconds can be represented by the type out_T:
370 // TODO: hopefully this isn't optimized away!
371 if (number / 1000 * 1000 != number) return false;
372 else seconds = number / 1000;
373 }
374 else return false; // no other suffix is allowed
375 }
376 }
377 else if (colons == 1 || colons == 2)
378 {
379 // check if there is a plus or minus sign
380 bool negative = false;
381 iss >> std::ws; // remove leading whitespace
382 if (iss.peek() == '-')
383 {
384 iss.ignore();
385 negative = true;
386 }
387 // it doesn't matter if there is a '+' sign.
388
389 long int hours = 0;
390 int minutes; // maximum: 59
391
392 if (colons == 1)
393 {
394 if ((iss >> minutes).fail()) return false;
395 // attention: the sign was already removed before!
396 if (minutes < 0 || minutes > 59) return false;
397 }
398 else if (colons == 2)
399 {
400 iss >> hours
401 >> std::noskipws // from now on, no whitespace is allowed
402 >> remove_colon; // read one character and check if it's a colon
403 convert_chars<2>(iss, minutes); // read minutes as two characters
404 if (iss.fail()) return false;
405 if (hours < 0) return false; // the sign was already removed before!
406 if (minutes > 59) return false;
407 }
408
409 out_T whole_seconds;
410 out_T fraction_of_second(0);
411
412 iss
413 >> std::noskipws // no whitespace is allowed
414 >> remove_colon; // read one character and check if it's a colon
415 convert_chars<2>(iss, whole_seconds); // read first two digits of seconds
416 if (iss.fail()) return false;
417
418 if (whole_seconds > 59) return false;
419
420 if (iss.peek() == '.')
421 {
422 if ((iss >> fraction_of_second).fail()) return false;
423 }
424
425 if (!(iss >> std::ws).eof()) return false; // nothing else is allowed!
426
427 auto the_rest = whole_seconds + fraction_of_second;
428
429 // the seconds part must be smaller than 60
430 if (the_rest >= 60) return false;
431
432 if (negative)
433 {
434 hours = -hours;
435 minutes = -minutes;
436 the_rest = -the_rest;
437 }
438
439 seconds = static_cast<out_T>(hours * 60 * 60);
440 seconds += static_cast<out_T>(minutes * 60);
441 seconds += the_rest;
442 }
443 else return false; // more than three colons are a deal-breaker!
444
445 output = seconds;
446 return true;
447}
448
457template<typename char_T, typename out_T>
458bool string2time(const char_T* input, out_T& output)
459{
460 return string2time(std::basic_string<char_T>(input), output);
461}
462
463} // namespace str
464} // namespace apf
465
466#endif
out_T S2RV(const std::string &input, out_T def)
Converter "String to Return Value".
Definition: stringtools.h:152
bool S2A(const std::string &input, out_T &output)
Converter "String to Anything".
Definition: stringtools.h:122
std::basic_istream< char_T, traits > & convert_chars(std::basic_istream< char_T, traits > &input, out_T &output)
Remove a specified number of characters from a stream and convert them to a numeric type.
Definition: stringtools.h:228
bool convert(std::istream &input, out_T &output)
Convert a stream to a given type.
Definition: stringtools.h:69
std::string A2S(const T &input)
Converter "Anything to String".
Definition: stringtools.h:52
bool string2time(const in_T< char_T, traits, Allocator > &input, out_T &output)
Convert time string to numeric value in seconds.
Definition: stringtools.h:330
std::basic_ios< char_T, traits > & clear_iostate_except_eof(std::basic_ios< char_T, traits > &stream)
Clear the state of a stream but leave eofbit as is.
Definition: stringtools.h:206
std::basic_istream< char_T, traits > & remove_char(std::basic_istream< char_T, traits > &input, const char_T character)
Remove a character from a stream and check if it is the one given as parameter.
Definition: stringtools.h:270
std::basic_istream< char_T, traits > & remove_colon(std::basic_istream< char_T, traits > &input)
Remove a colon from an input stream.
Definition: stringtools.h:304
Audio Processing Framework.
Definition: iterator.h:61