OpenMS  2.7.0
StringUtils.h
Go to the documentation of this file.
1 // --------------------------------------------------------------------------
2 // OpenMS -- Open-Source Mass Spectrometry
3 // --------------------------------------------------------------------------
4 // Copyright The OpenMS Team -- Eberhard Karls University Tuebingen,
5 // ETH Zurich, and Freie Universitaet Berlin 2002-2021.
6 //
7 // This software is released under a three-clause BSD license:
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of any author or any participating institution
14 // may be used to endorse or promote products derived from this software
15 // without specific prior written permission.
16 // For a full list of authors, refer to the file AUTHORS.
17 // --------------------------------------------------------------------------
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 // ARE DISCLAIMED. IN NO EVENT SHALL ANY OF THE AUTHORS OR THE CONTRIBUTING
22 // INSTITUTIONS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //
30 // --------------------------------------------------------------------------
31 // $Maintainer: Timo Sachsenberg, Chris Bielow $
32 // $Authors: Marc Sturm, Stephan Aiche, Chris Bielow $
33 // --------------------------------------------------------------------------
34 
35 #pragma once
36 
37 #include <OpenMS/CONCEPT/Types.h>
42 
43 #include <QtCore/QString>
44 #include <boost/spirit/include/qi.hpp>
45 #include <boost/spirit/include/karma.hpp>
46 #include <boost/type_traits.hpp>
47 
48 #include <string>
49 #include <vector>
50 
51 
52 namespace OpenMS
53 {
54  class String;
55 
56  namespace StringConversions
57  {
58 
59  // Karma full precision float policy
60  template <typename T>
61  class BK_PrecPolicy : public boost::spirit::karma::real_policies<T>
62  {
63  typedef boost::spirit::karma::real_policies<T> base_policy_type;
64  public:
65  static unsigned precision(T /*n*/)
66  {
67  /* The following would be the only way for a lossless double-string-double
68  * roundtrip but:
69  * a) We only care about speed
70  * b) Many tests have to be changed
71  * c) In the end boost::karma is bugged and hard limits the fractional digits
72  * even though you have leading zeros (basically forcing scientific notation)
73  * for full precision https://github.com/boostorg/spirit/issues/585
74  if (BK_PrecPolicy::floatfield(n))
75  {
76  T abs_n = boost::spirit::traits::get_absolute_value(n);
77  if (abs_n >= 1)
78  {
79  return std::numeric_limits<T>::max_digits10 - (floor(log10(abs_n)) + 1);
80  }
81  else
82  {
83  return std::numeric_limits<T>::max_digits10 - (floor(log10(abs_n)));
84  }
85  }
86  else
87  {
88  return std::numeric_limits<T>::max_digits10 - 1;
89  }
90  */
91  return writtenDigits<T>();
92  }
93 
94  // we want the numbers always to be in scientific format
95  static unsigned floatfield(T n)
96  {
97  if (boost::spirit::traits::test_zero(n))
98  return base_policy_type::fmtflags::fixed;
99 
100  T abs_n = boost::spirit::traits::get_absolute_value(n);
101  // this is due to a bug in downstream thirdparty tools that only can read
102  // up to 19 digits. https://github.com/OpenMS/OpenMS/issues/4627
103  return (abs_n >= 1e4 || abs_n < 1e-2)
104  ? base_policy_type::fmtflags::scientific : base_policy_type::fmtflags::fixed;
105  }
106  };
107  typedef boost::spirit::karma::real_generator<float, BK_PrecPolicy<float> > BK_PrecPolicyFloat_type;
109  typedef boost::spirit::karma::real_generator<double, BK_PrecPolicy<double> > BK_PrecPolicyDouble_type;
111  typedef boost::spirit::karma::real_generator<long double, BK_PrecPolicy<long double> > BK_PrecPolicyLongDouble_type;
113 
114  // toString functions (single argument)
115 
118  template <typename T>
119  inline void append(const T& i, String& target)
120  {
121  std::back_insert_iterator<std::string> sink(target);
122  boost::spirit::karma::generate(sink, i);
123  }
124 
126  template <typename T>
127  inline String toString(const T& i)
128  {
129  //std::stringstream s;
130  //s << i;
131  //return s.str();
132  String str;
133  append(i, str);
134  return str;
135  }
136 
137 
140  inline void appendLowP(float f, String& target)
141  {
142  std::back_insert_iterator<std::string> sink(target);
143  boost::spirit::karma::generate(sink, f);
144  }
146  inline String toStringLowP(float f)
147  {
148  String str;
149  appendLowP(f, str);
150  return str;
151  }
152 
153 
156  inline void appendLowP(double d, String& target)
157  {
158  std::back_insert_iterator<std::string> sink(target);
159  boost::spirit::karma::generate(sink, d);
160  }
162  inline String toStringLowP(double d)
163  {
164  String str;
165  appendLowP(d, str);
166  return str;
167  }
168 
169 
171  inline void appendLowP(long double ld, String& target)
172  {
173  std::back_insert_iterator<std::string> sink(target);
174  boost::spirit::karma::generate(sink, ld);
175  }
177  inline String toStringLowP(long double ld)
178  {
179  String str;
180  appendLowP(ld, str);
181  return str;
182  }
183 
184 
185 
187  inline void append(float f, String& target)
188  {
189  std::back_insert_iterator<std::string> sink(target);
190  boost::spirit::karma::generate(sink, BK_PrecPolicyFloat, f);
191  }
193  inline String toString(float f)
194  {
195  String str;
196  append(f, str);
197  return str;
198  }
199 
200 
201 
203  inline void append(double d, String& target)
204  {
205  std::back_insert_iterator<std::string> sink(target);
206  boost::spirit::karma::generate(sink, BK_PrecPolicyDouble, d);
207  }
209  inline String toString(double d)
210  {
211  String str;
212  append(d, str);
213  return str;
214  }
215 
216 
218  inline void append(long double ld, String& target)
219  {
220  std::back_insert_iterator<std::string> sink(target);
221  boost::spirit::karma::generate(sink, BK_PrecPolicyLongDouble, ld);
222  }
224  inline String toString(long double ld)
225  {
226  String str;
227  append(ld, str);
228  return str;
229  }
230 
231 
232  inline void append(const DataValue& d, bool full_precision, String& target)
233  {
234  target += d.toString(full_precision);
235  }
236  inline String toString(const DataValue& d, bool full_precision)
237  {
238  return d.toString(full_precision);
239  }
240 
241 
242 
243  inline String toString(const char c)
244  {
245  return std::string(1, c);
246  }
247 
248  inline String toString(const std::string& s)
249  {
250  return s;
251  }
252 
253  inline String toString(const char* s)
254  {
255  return std::string(s);
256  }
257 
259  inline String toString()
260  {
261  return String();
262  }
263 
264  inline String toString(const char* s, size_t length)
265  {
266  String res;
267  size_t count = 0;
268  while (count < length)
269  {
270  res += *(s + count);
271  ++count;
272  }
273  return res;
274  }
275  }
276 
277  class OPENMS_DLLAPI StringUtils
278  {
279 
280 public:
281 
282  //
284  //
285  static String numberLength(double d, UInt n)
286  {
287  std::stringstream s;
288  //reserve one space for the minus sign
289  Int sign = 0;
290  if (d < 0)
291  sign = 1;
292  d = fabs(d);
293 
294  if (d < pow(10.0, Int(n - sign - 2)))
295  {
296  s.precision(writtenDigits(d));
297  if (sign == 1)
298  s << "-";
299  s << d;
300  }
301  else
302  {
303  UInt exp = 0;
304  while (d > pow(10.0, Int(n - sign - 4)))
305  {
306  d /= 10;
307  ++exp;
308  }
309  d = Int(d) / 10.0;
310  exp += 1;
311  if (sign == 1)
312  s << "-";
313  s << d << "e";
314  if (exp < 10)
315  s << "0";
316  s << exp;
317  }
318  return s.str().substr(0, n);
319  }
320 
321  static String number(double d, UInt n)
322  {
323  return QString::number(d, 'f', n);
324  }
325 
326  static String& fillLeft(String & this_s, char c, UInt size)
327  {
328  if (this_s.size() < size)
329  {
330  this_s.std::string::operator=(String(size - this_s.size(), c) + this_s);
331  }
332  return this_s;
333  }
334 
335  static String& fillRight(String & this_s, char c, UInt size)
336  {
337  if (this_s.size() < size)
338  {
339  this_s.std::string::operator=(this_s + String(size - this_s.size(), c));
340  }
341  return this_s;
342  }
343 
344 
345  static bool hasPrefix(const String & this_s, const String & string)
346  {
347  if (string.size() > this_s.size())
348  {
349  return false;
350  }
351  if (string.empty())
352  {
353  return true;
354  }
355  return this_s.compare(0, string.size(), string) == 0;
356  }
357 
358  static bool hasSuffix(const String & this_s, const String& string)
359  {
360  if (string.size() > this_s.size())
361  {
362  return false;
363  }
364  if (string.empty())
365  {
366  return true;
367  }
368  return this_s.compare(this_s.size() - string.size(), string.size(), string) == 0;
369  }
370 
371  static bool hasSubstring(const String & this_s, const String& string)
372  {
373  return this_s.find(string) != std::string::npos;
374  }
375 
376  static bool has(const String & this_s, Byte byte)
377  {
378  return this_s.find(char(byte)) != std::string::npos;
379  }
380 
381  static String prefix(const String & this_s, size_t length)
382  {
383  if (length > this_s.size())
384  {
385  throw Exception::IndexOverflow(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, length, this_s.size());
386  }
387  return this_s.substr(0, length);
388  }
389 
390  static String suffix(const String & this_s, size_t length)
391  {
392  if (length > this_s.size())
393  {
394  throw Exception::IndexOverflow(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, length, this_s.size());
395  }
396  return this_s.substr(this_s.size() - length, length);
397  }
398 
399  static String prefix(const String & this_s, Int length)
400  {
401  if (length < 0)
402  {
403  throw Exception::IndexUnderflow(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, length, 0);
404  }
405  if (length > Int(this_s.size()))
406  {
407  throw Exception::IndexOverflow(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, length, this_s.size());
408  }
409  return this_s.substr(0, length);
410  }
411 
412  static String suffix(const String & this_s, Int length)
413  {
414  if (length < 0)
415  {
416  throw Exception::IndexUnderflow(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, length, 0);
417  }
418  if (length > Int(this_s.size()))
419  {
420  throw Exception::IndexOverflow(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, length, this_s.size());
421  }
422  return this_s.substr(this_s.size() - length, length);
423  }
424 
425  static String prefix(const String & this_s, char delim)
426  {
427  Size pos = this_s.find(delim);
428  if (pos == std::string::npos) //char not found
429  {
430  throw Exception::ElementNotFound(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION,
431  String(delim));
432  }
433  return this_s.substr(0, pos);
434  }
435 
436  static String suffix(const String & this_s, char delim)
437  {
438  Size pos = this_s.rfind(delim);
439  if (pos == std::string::npos) //char not found
440  {
441  throw Exception::ElementNotFound(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION,
442  String(delim));
443  }
444  return this_s.substr(++pos);
445  }
446 
447  static String substr(const String & this_s, size_t pos, size_t n)
448  {
449  Size begin = std::min(pos, this_s.size());
450  return static_cast<String>(this_s.std::string::substr(begin, n));
451  }
452 
453  static String chop(const String & this_s, Size n)
454  {
455  Size end = 0;
456  if (n < this_s.size())
457  {
458  end = this_s.size() - n;
459  }
460  return String(this_s.begin(), this_s.begin() + end);
461  }
462 
463  static String& trim(String & this_s)
464  {
465  //search for the begin of truncated string
466  std::string::iterator begin = this_s.begin();
467  while (begin != this_s.end() && (*begin == ' ' || *begin == '\t' || *begin == '\n' || *begin == '\r'))
468  {
469  ++begin;
470  }
471 
472  //all characters are whitespaces
473  if (begin == this_s.end())
474  {
475  this_s.clear();
476  return this_s;
477  }
478 
479  //search for the end of truncated string
480  std::string::iterator end = this_s.end();
481  end--;
482  while (end != begin && (*end == ' ' || *end == '\n' || *end == '\t' || *end == '\r'))
483  {
484  --end;
485  }
486  ++end;
487 
488  //no characters are whitespaces
489  if (begin == this_s.begin() && end == this_s.end())
490  {
491  return this_s;
492  }
493 
494  // TODO:
495  // string::operator=(std::string(begin, end));
496  this_s.std::string::operator=(std::string(begin, end));
497 
498  return this_s;
499  }
500 
501  static String& quote(String & this_s, char q, String::QuotingMethod method)
502  {
503  if (method == String::ESCAPE)
504  {
505  this_s.substitute(String(R"(\)"), String(R"(\\)"));
506  this_s.substitute(String(q), R"(\)" + String(q));
507  }
508  else if (method == String::DOUBLE)
509  this_s.substitute(String(q), String(q) + String(q));
510  this_s.std::string::operator=(q + this_s + q);
511  return this_s;
512  }
513 
514  static String& unquote(String & this_s, char q, String::QuotingMethod method)
515  {
516  // check if input string matches output format of the "quote" method:
517  if ((this_s.size() < 2) || (this_s[0] != q) || (this_s[this_s.size() - 1] != q))
518  {
520  __FILE__, __LINE__, OPENMS_PRETTY_FUNCTION,
521  "'" + this_s + "' does not have the expected format of a quoted string");
522  }
523  this_s.std::string::operator=(this_s.substr(1, this_s.size() - 2)); // remove quotation marks
524  if (method == String::ESCAPE)
525  {
526  this_s.substitute(R"(\)" + String(q), String(q));
527  this_s.substitute(String(R"(\\)"), String(R"(\)"));
528  }
529  else if (method == String::DOUBLE)
530  this_s.substitute(String(q) + String(q), String(q));
531  return this_s;
532  }
533 
534  static String& simplify(String & this_s)
535  {
536  String simple;
537 
538  bool last_was_whitespace = false;
539  for (std::string::iterator it = this_s.begin(); it != this_s.end(); ++it)
540  {
541  if (*it == ' ' || *it == '\n' || *it == '\t' || *it == '\r')
542  {
543  if (!last_was_whitespace)
544  {
545  simple += ' ';
546  }
547  last_was_whitespace = true;
548  }
549  else
550  {
551  simple += *it;
552  last_was_whitespace = false;
553  }
554  }
555 
556  this_s.swap(simple);
557  return this_s;
558  }
559 
560  static String random(UInt length)
561  {
562  srand(time(nullptr));
563  String tmp(length, '.');
564  size_t random;
565  for (Size i = 0; i < length; ++i)
566  {
567  random = static_cast<size_t>(floor((static_cast<double>(rand()) / (double(RAND_MAX) + 1)) * 62.0));
568  if (random < 10)
569  {
570  tmp[i] = static_cast<char>(random + 48);
571  }
572  else if (random < 36)
573  {
574  tmp[i] = static_cast<char>(random + 55);
575  }
576  else
577  {
578  tmp[i] = static_cast<char>(random + 61);
579  }
580  }
581  return tmp;
582  }
583 
584  static String& reverse(String & this_s)
585  {
586  String tmp = this_s;
587  for (Size i = 0; i != this_s.size(); ++i)
588  {
589  this_s[i] = tmp[this_s.size() - 1 - i];
590  }
591  return this_s;
592  }
593 
594  static bool split(const String & this_s, const char splitter, std::vector<String>& substrings,
595  bool quote_protect)
596  {
597  substrings.clear();
598  if (this_s.empty())
599  return false;
600 
601  Size nsplits = count(this_s.begin(), this_s.end(), splitter);
602 
603  if (!quote_protect && (nsplits == 0))
604  {
605  substrings.push_back(this_s);
606  return false;
607  }
608 
609  // splitter(s) found
610  substrings.reserve(nsplits + 1);
611 
612  // why is "this_s." needed here?
613  std::string::const_iterator begin = this_s.begin();
614  std::string::const_iterator end = this_s.begin();
615 
616  if (quote_protect)
617  {
618  Int quote_count(0);
619  for (; end != this_s.end(); ++end)
620  {
621  if (*end == '"')
622  {
623  ++quote_count;
624  }
625  if ((quote_count % 2 == 0) && (*end == splitter))
626  {
627  String block = String(begin, end);
628  block.trim();
629  if ((block.size() >= 2) && ((block.prefix(1) == String("\"")) ^
630  (block.suffix(1) == String("\""))))
631  { // block has start or end quote, but not both
632  // (one quote is somewhere in the middle)
634  __FILE__, __LINE__, OPENMS_PRETTY_FUNCTION,
635  String("Could not dequote string '") + block +
636  "' due to wrongly placed '\"'.");
637  }
638  else if ((block.size() >= 2) && (block.prefix(1) == String("\"")) &&
639  (block.suffix(1) == String("\"")))
640  { // block has start and end quotes --> remove them
641  block = block.substr(1, block.size() - 2);
642  }
643  substrings.push_back(block);
644  begin = end + 1;
645  }
646  }
647  // no valid splitter found - return empty list
648  if (substrings.empty())
649  {
650  substrings.push_back(this_s);
651  return false;
652  }
653 
654  String block = String(begin, end);
655  block.trim();
656  if ((block.size() >= 2) && ((block.prefix(1) == String("\"")) ^
657  (block.suffix(1) == String("\""))))
658  { // block has start or end quote but not both
659  // (one quote is somewhere in the middle)
661  __FILE__, __LINE__, OPENMS_PRETTY_FUNCTION,
662  String("Could not dequote string '") + block +
663  "' due to wrongly placed '\"'.");
664  }
665  else if ((block.size() >= 2) && (block.prefix(1) == String("\"")) &&
666  (block.suffix(1) == String("\"")))
667  { // block has start and end quotes --> remove them
668  block = block.substr(1, block.size() - 2);
669  }
670  substrings.push_back(block);
671  }
672  else // do not honor quotes
673  {
674  for (; end != this_s.end(); ++end)
675  {
676  if (*end == splitter)
677  {
678  substrings.push_back(String(begin, end));
679  begin = end + 1;
680  }
681  }
682  substrings.push_back(String(begin, end));
683  }
684 
685  // at this point we are sure that there are at least two components
686  return true;
687  }
688 
689  static bool split(const String & this_s, const String& splitter, std::vector<String>& substrings)
690  {
691  substrings.clear();
692  if (this_s.empty())
693  return false;
694 
695  if (splitter.empty()) // split after every character:
696  {
697  substrings.resize(this_s.size());
698  for (Size i = 0; i < this_s.size(); ++i)
699  substrings[i] = this_s[i];
700  return true;
701  }
702 
703  Size len = splitter.size(), start = 0, pos = this_s.find(splitter);
704  if (len == 0)
705  len = 1;
706  while (pos != std::string::npos)
707  {
708  substrings.push_back(this_s.substr(start, pos - start));
709  start = pos + len;
710  pos = this_s.find(splitter, start);
711  }
712  substrings.push_back(this_s.substr(start, this_s.size() - start));
713  return substrings.size() > 1;
714  }
715 
716  static bool split_quoted(const String & this_s, const String& splitter, std::vector<String>& substrings,
717  char q, String::QuotingMethod method)
718  {
719  substrings.clear();
720  if (this_s.empty() || splitter.empty())
721  return false;
722 
723  bool in_quote = false;
724  char targets[2] = {q, splitter[0]}; // targets for "find_first_of"
725  std::string rest = splitter.substr(1, splitter.size() - 1);
726  Size start = 0;
727  for (Size i = 0; i < this_s.size(); ++i)
728  {
729  if (in_quote) // skip to closing quotation mark
730  {
731  bool embedded = false;
732  if (method == String::ESCAPE)
733  {
734  for (; i < this_s.size(); ++i)
735  {
736  if (this_s[i] == '\\')
737  embedded = !embedded;
738  else if ((this_s[i] == q) && !embedded)
739  break;
740  else
741  embedded = false;
742  }
743  }
744  else // method: NONE or DOUBLE
745  {
746  for (; i < this_s.size(); ++i)
747  {
748  if (this_s[i] == q)
749  {
750  if (method == String::NONE)
751  break; // found
752  // next character is also closing quotation mark:
753  if ((i < this_s.size() - 1) && (this_s[i + 1] == q))
754  embedded = !embedded;
755  // even number of subsequent quotes (doubled) => found
756  else if (!embedded)
757  break;
758  // odd number of subsequent quotes => belongs to a pair
759  else
760  embedded = false;
761  }
762  }
763  }
764  in_quote = false; // end of quote reached
765  }
766  else
767  {
768  i = this_s.find_first_of(targets, i, 2);
769  if (i == std::string::npos)
770  break; // nothing found
771  if (this_s[i] == q)
772  in_quote = true;
773  else if (this_s.compare(i + 1, rest.size(), rest) == 0) // splitter found
774  {
775  substrings.push_back(this_s.substr(start, i - start));
776  start = i + splitter.size();
777  i = start - 1; // increased by loop
778  }
779  }
780  }
781  if (in_quote) // reached end without finding closing quotation mark
782  {
784  __FILE__, __LINE__, OPENMS_PRETTY_FUNCTION,
785  "unbalanced quotation marks in string '" + this_s + "'");
786  }
787  substrings.push_back(this_s.substr(start, this_s.size() - start));
788  return substrings.size() > 1;
789  }
790 
791  static QString toQString(const String & this_s)
792  {
793  return QString(this_s.c_str());
794  }
795 
796  static Int toInt(const String & this_s)
797  {
798  Int ret;
799 
800  // boost::spirit::qi was found to be vastly superior to boost::lexical_cast or stringstream extraction (especially for VisualStudio),
801  // so don't change this unless you have benchmarks for all platforms!
802  String::ConstIterator it = this_s.begin();
803  if (!boost::spirit::qi::phrase_parse(it, this_s.end(), boost::spirit::qi::int_, boost::spirit::ascii::space, ret))
804  {
805  throw Exception::ConversionError(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, String("Could not convert string '") + this_s + "' to an integer value");
806  }
807  // was the string parsed (white spaces are skipped automatically!) completely? If not, we have a problem because a previous split might have used the wrong split char
808  if (it != this_s.end())
809  {
810  throw Exception::ConversionError(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, String("Prefix of string '") + this_s + "' successfully converted to an integer value. Additional characters found at position " + (int)(distance(this_s.begin(), it) + 1));
811  }
812  return ret;
813  }
814 
815  static float toFloat(const String& this_s)
816  {
817  float ret;
818 
819  // boost::spirit::qi was found to be vastly superior to boost::lexical_cast or stringstream extraction (especially for VisualStudio),
820  // so don't change this unless you have benchmarks for all platforms!
821  String::ConstIterator it = this_s.begin();
822  if (!boost::spirit::qi::phrase_parse(it, this_s.end(), parse_float_, boost::spirit::ascii::space, ret))
823  {
824  throw Exception::ConversionError(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, String("Could not convert string '") + this_s + "' to a float value");
825  }
826  // was the string parsed (white spaces are skipped automatically!) completely? If not, we have a problem because a previous split might have used the wrong split char
827  if (it != this_s.end())
828  {
829  throw Exception::ConversionError(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, String("Prefix of string '") + this_s + "' successfully converted to a float value. Additional characters found at position " + (int)(distance(this_s.begin(), it) + 1));
830  }
831  return ret;
832  }
833 
841  static double toDouble(const String& s)
842  {
843  double ret;
844  // boost::spirit::qi was found to be vastly superior to boost::lexical_cast or stringstream extraction (especially for VisualStudio),
845  // so don't change this unless you have benchmarks for all platforms!
846  String::ConstIterator it = s.begin();
847  if (!boost::spirit::qi::phrase_parse(it, s.end(), parse_double_, boost::spirit::ascii::space, ret))
848  {
849  throw Exception::ConversionError(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, String("Could not convert string '") + s + "' to a double value");
850  }
851  // was the string parsed (white spaces are skipped automatically!) completely? If not, we have a problem because a previous split might have used the wrong split char
852  if (it != s.end())
853  {
854  throw Exception::ConversionError(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, String("Prefix of string '") + s + "' successfully converted to a double value. Additional characters found at position " + (int)(distance(s.begin(), it) + 1));
855  }
856  return ret;
857  }
858 
863  template <typename IteratorT>
864  static bool extractDouble(IteratorT& begin, const IteratorT& end, double& target)
865  {
866  // boost::spirit::qi was found to be vastly superior to boost::lexical_cast or stringstream extraction (especially for VisualStudio),
867  // so don't change this unless you have benchmarks for all platforms!
868 
869  // qi::parse() does not consume whitespace before or after the double (qi::parse_phrase() would).
870  return boost::spirit::qi::parse(begin, end, parse_double_, target);
871  }
872 
873 
874  static String& toUpper(String & this_s)
875  {
876  std::transform(this_s.begin(), this_s.end(), this_s.begin(), (int (*)(int))toupper);
877  return this_s;
878  }
879 
880  static String& firstToUpper(String & this_s)
881  {
882  if (this_s.size() != 0)
883  {
884  this_s[0] = toupper(this_s[0]);
885  }
886  return this_s;
887  }
888 
889  static String& toLower(String & this_s)
890  {
891  std::transform(this_s.begin(), this_s.end(), this_s.begin(), (int (*)(int))tolower);
892  return this_s;
893  }
894 
895  static String& substitute(String & this_s, char from, char to)
896  {
897  std::replace(this_s.begin(), this_s.end(), from, to);
898  return this_s;
899  }
900 
901  static String& substitute(String & this_s, const String& from, const String& to)
902  {
903  if (!from.empty())
904  {
905  std::vector<String> parts;
906  this_s.split(from, parts);
907  this_s.concatenate(parts.begin(), parts.end(), to);
908  }
909  return this_s;
910  }
911 
912  static String& remove(String & this_s, char what)
913  {
914  this_s.erase(std::remove(this_s.begin(), this_s.end(), what), this_s.end());
915  return this_s;
916  }
917 
918  static String& ensureLastChar(String & this_s, char end)
919  {
920  if (!this_s.hasSuffix(end))
921  this_s.append(1, end);
922  return this_s;
923  }
924 
925  static String& removeWhitespaces(String& this_s)
926  {
927  std::string::const_iterator it = this_s.begin();
928  std::string::iterator dest = this_s.begin();
929  std::string::const_iterator it_end = this_s.end();
930  bool has_spaces(false);
931  while (it != it_end)
932  {
933  const char c = *it;
934  if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
935  {
936  ++it;
937  has_spaces = true;
938  continue; // no need to copy a whitespace
939  }
940  // copy to the left, if we had a whitespace before
941  if (has_spaces) *dest = *it;
942  // advance both
943  ++dest;
944  ++it;
945  }
946 
947  // shorten result
948  if (has_spaces) this_s.resize(dest - this_s.begin());
949 
950  return this_s;
951  }
952 
953  private:
954 
955  /*
956  @brief A fixed Boost:pi real parser policy, capable of dealing with 'nan' without crashing
957 
958  The original Boost implementation has a bug, see https://svn.boost.org/trac/boost/ticket/6955.
959  Can be removed if Boost 1.60 or above is required
960 
961  */
962  template <typename T>
964  {
965  template <typename Iterator, typename Attribute>
966  static bool
967  parse_nan(Iterator& first, Iterator const& last, Attribute& attr_)
968  {
969  if (first == last)
970  return false; // end of input reached
971 
972  if (*first != 'n' && *first != 'N')
973  return false; // not "nan"
974 
975  // nan[(...)] ?
976  if (boost::spirit::qi::detail::string_parse("nan", "NAN", first, last, boost::spirit::qi::unused))
977  {
978  if (first != last && *first == '(') /* this check is broken in boost 1.49 - (at least) 1.54; fixed in 1.60 */
979  {
980  // skip trailing (...) part
981  Iterator i = first;
982 
983  while (++i != last && *i != ')')
984  ;
985  if (i == last)
986  return false; // no trailing ')' found, give up
987 
988  first = ++i;
989  }
990  attr_ = std::numeric_limits<T>::quiet_NaN();
991  return true;
992  }
993  return false;
994  }
995  };
996 
997  // Qi parsers using the 'real_policies_NANfixed_' template which allows for 'nan'
998  // (the original Boost implementation has a bug, see https://svn.boost.org/trac/boost/ticket/6955)
999  static boost::spirit::qi::real_parser<double, real_policies_NANfixed_<double> > parse_double_;
1000  static boost::spirit::qi::real_parser<float, real_policies_NANfixed_<float> > parse_float_;
1001 
1002  };
1003 
1004 } // namespace OPENMS
1005 
Class to hold strings, numeric values, lists of strings and lists of numeric values.
Definition: DataValue.h:59
String toString(bool full_precision=true) const
Conversion to String full_precision Controls number of fractional digits for all double types or list...
Invalid conversion exception.
Definition: Exception.h:356
Element could not be found exception.
Definition: Exception.h:670
Int overflow exception.
Definition: Exception.h:248
Int underflow exception.
Definition: Exception.h:210
Definition: StringUtils.h:62
static unsigned precision(T)
Definition: StringUtils.h:65
static unsigned floatfield(T n)
Definition: StringUtils.h:95
boost::spirit::karma::real_policies< T > base_policy_type
Definition: StringUtils.h:63
Definition: StringUtils.h:278
static String & substitute(String &this_s, const String &from, const String &to)
Definition: StringUtils.h:901
static double toDouble(const String &s)
convert String (leading and trailing whitespace allowed) to double
Definition: StringUtils.h:841
static String & toUpper(String &this_s)
Definition: StringUtils.h:874
static String chop(const String &this_s, Size n)
Definition: StringUtils.h:453
static bool extractDouble(IteratorT &begin, const IteratorT &end, double &target)
Definition: StringUtils.h:864
static bool split(const String &this_s, const char splitter, std::vector< String > &substrings, bool quote_protect)
Definition: StringUtils.h:594
static QString toQString(const String &this_s)
Definition: StringUtils.h:791
static String & substitute(String &this_s, char from, char to)
Definition: StringUtils.h:895
static bool hasPrefix(const String &this_s, const String &string)
Definition: StringUtils.h:345
static String suffix(const String &this_s, char delim)
Definition: StringUtils.h:436
static String & fillLeft(String &this_s, char c, UInt size)
Definition: StringUtils.h:326
static Int toInt(const String &this_s)
Definition: StringUtils.h:796
static float toFloat(const String &this_s)
Definition: StringUtils.h:815
static String & simplify(String &this_s)
Definition: StringUtils.h:534
static String & firstToUpper(String &this_s)
Definition: StringUtils.h:880
static String & toLower(String &this_s)
Definition: StringUtils.h:889
static String prefix(const String &this_s, char delim)
Definition: StringUtils.h:425
static boost::spirit::qi::real_parser< double, real_policies_NANfixed_< double > > parse_double_
Definition: StringUtils.h:999
static bool hasSubstring(const String &this_s, const String &string)
Definition: StringUtils.h:371
static boost::spirit::qi::real_parser< float, real_policies_NANfixed_< float > > parse_float_
Definition: StringUtils.h:1000
static String suffix(const String &this_s, size_t length)
Definition: StringUtils.h:390
static String numberLength(double d, UInt n)
Functions.
Definition: StringUtils.h:285
static String & trim(String &this_s)
Definition: StringUtils.h:463
static bool hasSuffix(const String &this_s, const String &string)
Definition: StringUtils.h:358
static String suffix(const String &this_s, Int length)
Definition: StringUtils.h:412
static bool has(const String &this_s, Byte byte)
Definition: StringUtils.h:376
static String random(UInt length)
Definition: StringUtils.h:560
static bool split_quoted(const String &this_s, const String &splitter, std::vector< String > &substrings, char q, String::QuotingMethod method)
Definition: StringUtils.h:716
static String prefix(const String &this_s, Int length)
Definition: StringUtils.h:399
static String substr(const String &this_s, size_t pos, size_t n)
Definition: StringUtils.h:447
static String & ensureLastChar(String &this_s, char end)
Definition: StringUtils.h:918
static String number(double d, UInt n)
Definition: StringUtils.h:321
static String & fillRight(String &this_s, char c, UInt size)
Definition: StringUtils.h:335
static String & remove(String &this_s, char what)
Definition: StringUtils.h:912
static String & unquote(String &this_s, char q, String::QuotingMethod method)
Definition: StringUtils.h:514
static String prefix(const String &this_s, size_t length)
Definition: StringUtils.h:381
static String & removeWhitespaces(String &this_s)
Definition: StringUtils.h:925
static bool split(const String &this_s, const String &splitter, std::vector< String > &substrings)
Definition: StringUtils.h:689
static String & quote(String &this_s, char q, String::QuotingMethod method)
Definition: StringUtils.h:501
static String & reverse(String &this_s)
Definition: StringUtils.h:584
A more convenient string class.
Definition: String.h:61
String substr(size_t pos=0, size_t n=npos) const
Wrapper for the STL substr() method. Returns a String object with its contents initialized to a subst...
String prefix(SizeType length) const
returns the prefix of length length
const_iterator ConstIterator
Const Iterator.
Definition: String.h:73
QuotingMethod
How to handle embedded quotes when quoting strings.
Definition: String.h:82
@ ESCAPE
Definition: String.h:82
@ DOUBLE
Definition: String.h:82
@ NONE
Definition: String.h:82
bool split(const char splitter, std::vector< String > &substrings, bool quote_protect=false) const
Splits a string into substrings using splitter as delimiter.
String & trim()
removes whitespaces (space, tab, line feed, carriage return) at the beginning and the end of the stri...
String & substitute(char from, char to)
Replaces all occurrences of the character from by the character to.
bool hasSuffix(const String &string) const
true if String ends with string, false otherwise
String suffix(SizeType length) const
returns the suffix of length length
void concatenate(StringIterator first, StringIterator last, const String &glue="")
Concatenates all elements from first to last-1 and inserts glue between the elements.
Definition: String.h:467
OPENMS_BYTE_TYPE Byte
Byte type.
Definition: Types.h:111
int Int
Signed integer type.
Definition: Types.h:102
unsigned int UInt
Unsigned integer type.
Definition: Types.h:94
size_t Size
Size type e.g. used as variable which can hold result of size()
Definition: Types.h:127
const double c
Definition: Constants.h:209
boost::spirit::karma::real_generator< long double, BK_PrecPolicy< long double > > BK_PrecPolicyLongDouble_type
Definition: StringUtils.h:111
boost::spirit::karma::real_generator< float, BK_PrecPolicy< float > > BK_PrecPolicyFloat_type
Definition: StringUtils.h:107
const BK_PrecPolicyLongDouble_type BK_PrecPolicyLongDouble
Definition: StringUtils.h:112
String toStringLowP(float f)
low precision (3 fractional digits) conversion to string (Karma default)
Definition: StringUtils.h:146
void appendLowP(float f, String &target)
Definition: StringUtils.h:140
const BK_PrecPolicyDouble_type BK_PrecPolicyDouble
Definition: StringUtils.h:110
String toString(const T &i)
fallback template for general purpose using Boost::Karma; more specializations below
Definition: StringUtils.h:127
void append(const T &i, String &target)
Definition: StringUtils.h:119
const BK_PrecPolicyFloat_type BK_PrecPolicyFloat
Definition: StringUtils.h:108
boost::spirit::karma::real_generator< double, BK_PrecPolicy< double > > BK_PrecPolicyDouble_type
Definition: StringUtils.h:109
Main OpenMS namespace.
Definition: FeatureDeconvolution.h:47
constexpr Int writtenDigits(const FloatingPointType &=FloatingPointType())
Number of digits commonly used for writing a floating point type (a.k.a. precision)....
Definition: Types.h:294
static bool parse_nan(Iterator &first, Iterator const &last, Attribute &attr_)
Definition: StringUtils.h:967