OpenMS
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
StringUtils.h
Go to the documentation of this file.
1 // Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin
2 // SPDX-License-Identifier: BSD-3-Clause
3 //
4 // --------------------------------------------------------------------------
5 // $Maintainer: Timo Sachsenberg, Chris Bielow $
6 // $Authors: Marc Sturm, Stephan Aiche, Chris Bielow $
7 // --------------------------------------------------------------------------
8 
9 #pragma once
10 
11 #include <OpenMS/CONCEPT/Types.h>
17 
18 #include <QtCore/QString>
19 #include <boost/spirit/include/qi.hpp>
20 #include <boost/spirit/include/karma.hpp>
21 #include <boost/type_traits.hpp>
22 
23 #include <string>
24 #include <vector>
25 
26 
27 namespace OpenMS
28 {
29  class String;
30 
31  class OPENMS_DLLAPI StringUtilsHelper
32  {
33 
34 public:
35 
36  //
38  //
39  static Int toInt32(const String& this_s)
40  {
41  Int ret;
42 
43  // boost::spirit::qi was found to be vastly superior to boost::lexical_cast or stringstream extraction (especially for VisualStudio),
44  // so don't change this unless you have benchmarks for all platforms!
45  String::ConstIterator it = this_s.begin();
46  if (!boost::spirit::qi::phrase_parse(it, this_s.end(), boost::spirit::qi::int_, boost::spirit::ascii::space, ret))
47  {
48  throw Exception::ConversionError(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, String("Could not convert string '") + this_s + "' to an integer value");
49  }
50  // 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
51  if (it != this_s.end())
52  {
53  throw Exception::ConversionError(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, String("Prefix of string '") + this_s + "' successfully converted to an int32 value. Additional characters found at position " + (int)(distance(this_s.begin(), it) + 1));
54  }
55  return ret;
56  }
57 
58  static Int64 toInt64(const String& this_s)
59  {
60  Int64 ret;
61 
62  // boost::spirit::qi was found to be vastly superior to boost::lexical_cast or stringstream extraction (especially for VisualStudio),
63  // so don't change this unless you have benchmarks for all platforms!
64  String::ConstIterator it = this_s.begin();
65  if (!boost::spirit::qi::phrase_parse(it, this_s.end(), boost::spirit::qi::long_long, boost::spirit::ascii::space, ret))
66  {
67  throw Exception::ConversionError(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, String("Could not convert string '") + this_s + "' to an int64 value");
68  }
69  // 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
70  if (it != this_s.end())
71  {
72  throw Exception::ConversionError(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION,
73  String("Prefix of string '") + this_s + "' successfully converted to an integer value. Additional characters found at position " +
74  (int)(distance(this_s.begin(), it) + 1));
75  }
76  return ret;
77  }
78 
79  static float toFloat(const String& this_s)
80  {
81  float ret;
82 
83  // boost::spirit::qi was found to be vastly superior to boost::lexical_cast or stringstream extraction (especially for VisualStudio),
84  // so don't change this unless you have benchmarks for all platforms!
85  String::ConstIterator it = this_s.begin();
86  if (!boost::spirit::qi::phrase_parse(it, this_s.end(), parse_float_, boost::spirit::ascii::space, ret))
87  {
88  throw Exception::ConversionError(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, String("Could not convert string '") + this_s + "' to a float value");
89  }
90  // 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
91  if (it != this_s.end())
92  {
93  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));
94  }
95  return ret;
96  }
97 
105  static double toDouble(const String& s)
106  {
107  double ret;
108  // boost::spirit::qi was found to be vastly superior to boost::lexical_cast or stringstream extraction (especially for VisualStudio),
109  // so don't change this unless you have benchmarks for all platforms!
110  String::ConstIterator it = s.begin();
111  if (!boost::spirit::qi::phrase_parse(it, s.end(), parse_double_, boost::spirit::ascii::space, ret))
112  {
113  throw Exception::ConversionError(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, String("Could not convert string '") + s + "' to a double value");
114  }
115  // 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
116  if (it != s.end())
117  {
118  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));
119  }
120  return ret;
121  }
122 
127  template <typename IteratorT>
128  static bool extractDouble(IteratorT& begin, const IteratorT& end, double& target)
129  {
130  // boost::spirit::qi was found to be vastly superior to boost::lexical_cast or stringstream extraction (especially for VisualStudio),
131  // so don't change this unless you have benchmarks for all platforms!
132 
133  // qi::parse() does not consume whitespace before or after the double (qi::parse_phrase() would).
134  return boost::spirit::qi::parse(begin, end, parse_double_, target);
135  }
136 
141  template <typename IteratorT>
142  static bool extractInt(IteratorT& begin, const IteratorT& end, int& target)
143  {
144  // qi::parse() does not consume whitespace before or after the int (qi::parse_phrase() would).
145  return boost::spirit::qi::parse(begin, end, parse_int_, target);
146  }
147 
148  private:
149 
150  /*
151  @brief A fixed Boost:pi real parser policy, capable of dealing with 'nan' without crashing
152 
153  The original Boost implementation has a bug, see https://svn.boost.org/trac/boost/ticket/6955.
154  Can be removed if Boost 1.60 or above is required
155 
156  */
157  template <typename T>
159  {
160  template <typename Iterator, typename Attribute>
161  static bool
162  parse_nan(Iterator& first, Iterator const& last, Attribute& attr_)
163  {
164  if (first == last)
165  return false; // end of input reached
166 
167  if (*first != 'n' && *first != 'N')
168  return false; // not "nan"
169 
170  // nan[(...)] ?
171  if (boost::spirit::qi::detail::string_parse("nan", "NAN", first, last, boost::spirit::qi::unused))
172  {
173  if (first != last && *first == '(') /* this check is broken in boost 1.49 - (at least) 1.54; fixed in 1.60 */
174  {
175  // skip trailing (...) part
176  Iterator i = first;
177 
178  while (++i != last && *i != ')')
179  ;
180  if (i == last)
181  return false; // no trailing ')' found, give up
182 
183  first = ++i;
184  }
185  attr_ = std::numeric_limits<T>::quiet_NaN();
186  return true;
187  }
188  return false;
189  }
190  };
191 
192  // Qi parsers using the 'real_policies_NANfixed_' template which allows for 'nan'
193  // (the original Boost implementation has a bug, see https://svn.boost.org/trac/boost/ticket/6955)
194  static boost::spirit::qi::real_parser<double, real_policies_NANfixed_<double> > parse_double_;
195  static boost::spirit::qi::real_parser<float, real_policies_NANfixed_<float> > parse_float_;
196  static boost::spirit::qi::int_parser<> parse_int_;
197 
198  };
199 
200  namespace StringUtils
201  {
202 
203  [[maybe_unused]] static String number(double d, UInt n)
204  {
205  return QString::number(d, 'f', n);
206  }
207 
208  [[maybe_unused]] static QString toQString(const String & this_s)
209  {
210  return QString(this_s.c_str());
211  }
212 
213  [[maybe_unused]] static Int32 toInt32(const String & this_s)
214  {
215  return StringUtilsHelper::toInt32(this_s);
216  }
217 
218  [[maybe_unused]] static Int64 toInt64(const String& this_s)
219  {
220  return StringUtilsHelper::toInt64(this_s);
221  }
222 
223  [[maybe_unused]] static float toFloat(const String & this_s)
224  {
225  return StringUtilsHelper::toFloat(this_s);
226  }
227 
228  [[maybe_unused]] static double toDouble(const String & this_s)
229  {
230  return StringUtilsHelper::toDouble(this_s);
231  }
232 
233  template <typename IteratorT>
234  static bool extractDouble(IteratorT& begin, const IteratorT& end, double& target)
235  {
236  return StringUtilsHelper::extractDouble(begin, end, target);
237  }
238 
239  template <typename IteratorT>
240  static bool extractInt(IteratorT& begin, const IteratorT& end, int& target)
241  {
242  return StringUtilsHelper::extractInt(begin, end, target);
243  }
244  }
245 } // namespace OPENMS
246 
Invalid conversion exception.
Definition: Exception.h:330
Definition: StringUtils.h:32
static double toDouble(const String &s)
convert String (leading and trailing whitespace allowed) to double
Definition: StringUtils.h:105
static boost::spirit::qi::int_parser parse_int_
Definition: StringUtils.h:196
static bool extractDouble(IteratorT &begin, const IteratorT &end, double &target)
Definition: StringUtils.h:128
static Int64 toInt64(const String &this_s)
Definition: StringUtils.h:58
static float toFloat(const String &this_s)
Definition: StringUtils.h:79
static Int toInt32(const String &this_s)
Functions.
Definition: StringUtils.h:39
static boost::spirit::qi::real_parser< double, real_policies_NANfixed_< double > > parse_double_
Definition: StringUtils.h:194
static boost::spirit::qi::real_parser< float, real_policies_NANfixed_< float > > parse_float_
Definition: StringUtils.h:195
static bool extractInt(IteratorT &begin, const IteratorT &end, int &target)
Definition: StringUtils.h:142
A more convenient string class.
Definition: String.h:34
const_iterator ConstIterator
Const Iterator.
Definition: String.h:46
int32_t Int32
Signed integer type (32bit)
Definition: Types.h:26
int64_t Int64
Signed integer type (64bit)
Definition: Types.h:40
int Int
Signed integer type.
Definition: Types.h:72
unsigned int UInt
Unsigned integer type.
Definition: Types.h:64
static bool extractDouble(IteratorT &begin, const IteratorT &end, double &target)
Definition: StringUtils.h:234
static bool extractInt(IteratorT &begin, const IteratorT &end, int &target)
Definition: StringUtils.h:240
static String number(double d, UInt n)
Definition: StringUtils.h:203
static Int32 toInt32(const String &this_s)
Definition: StringUtils.h:213
static Int64 toInt64(const String &this_s)
Definition: StringUtils.h:218
static double toDouble(const String &this_s)
Definition: StringUtils.h:228
static float toFloat(const String &this_s)
Definition: StringUtils.h:223
static QString toQString(const String &this_s)
Definition: StringUtils.h:208
Main OpenMS namespace.
Definition: openswathalgo/include/OpenMS/OPENSWATHALGO/DATAACCESS/ISpectrumAccess.h:19
static bool parse_nan(Iterator &first, Iterator const &last, Attribute &attr_)
Definition: StringUtils.h:162