OpenMS
StringUtils.h
Go to the documentation of this file.
1 // Copyright (c) 2002-2023, The OpenMS Team -- 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 
137  private:
138 
139  /*
140  @brief A fixed Boost:pi real parser policy, capable of dealing with 'nan' without crashing
141 
142  The original Boost implementation has a bug, see https://svn.boost.org/trac/boost/ticket/6955.
143  Can be removed if Boost 1.60 or above is required
144 
145  */
146  template <typename T>
148  {
149  template <typename Iterator, typename Attribute>
150  static bool
151  parse_nan(Iterator& first, Iterator const& last, Attribute& attr_)
152  {
153  if (first == last)
154  return false; // end of input reached
155 
156  if (*first != 'n' && *first != 'N')
157  return false; // not "nan"
158 
159  // nan[(...)] ?
160  if (boost::spirit::qi::detail::string_parse("nan", "NAN", first, last, boost::spirit::qi::unused))
161  {
162  if (first != last && *first == '(') /* this check is broken in boost 1.49 - (at least) 1.54; fixed in 1.60 */
163  {
164  // skip trailing (...) part
165  Iterator i = first;
166 
167  while (++i != last && *i != ')')
168  ;
169  if (i == last)
170  return false; // no trailing ')' found, give up
171 
172  first = ++i;
173  }
174  attr_ = std::numeric_limits<T>::quiet_NaN();
175  return true;
176  }
177  return false;
178  }
179  };
180 
181  // Qi parsers using the 'real_policies_NANfixed_' template which allows for 'nan'
182  // (the original Boost implementation has a bug, see https://svn.boost.org/trac/boost/ticket/6955)
183  static boost::spirit::qi::real_parser<double, real_policies_NANfixed_<double> > parse_double_;
184  static boost::spirit::qi::real_parser<float, real_policies_NANfixed_<float> > parse_float_;
185 
186  };
187 
188  namespace StringUtils
189  {
190 
191  [[maybe_unused]] static String number(double d, UInt n)
192  {
193  return QString::number(d, 'f', n);
194  }
195 
196  [[maybe_unused]] static QString toQString(const String & this_s)
197  {
198  return QString(this_s.c_str());
199  }
200 
201  [[maybe_unused]] static Int32 toInt32(const String & this_s)
202  {
203  return StringUtilsHelper::toInt32(this_s);
204  }
205 
206  [[maybe_unused]] static Int64 toInt64(const String& this_s)
207  {
208  return StringUtilsHelper::toInt64(this_s);
209  }
210 
211  [[maybe_unused]] static float toFloat(const String & this_s)
212  {
213  return StringUtilsHelper::toFloat(this_s);
214  }
215 
216  [[maybe_unused]] static double toDouble(const String & this_s)
217  {
218  return StringUtilsHelper::toDouble(this_s);
219  }
220 
221  template <typename IteratorT>
222  static bool extractDouble(IteratorT& begin, const IteratorT& end, double& target)
223  {
224  return StringUtilsHelper::extractDouble(begin, end, target);
225  }
226 
227  }
228 } // namespace OPENMS
229 
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 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:183
static boost::spirit::qi::real_parser< float, real_policies_NANfixed_< float > > parse_float_
Definition: StringUtils.h:184
A more convenient string class.
Definition: String.h:34
const_iterator ConstIterator
Const Iterator.
Definition: String.h:46
int Int
Signed integer type.
Definition: Types.h:76
OPENMS_INT32_TYPE Int32
Signed integer type (32bit)
Definition: Types.h:30
OPENMS_INT64_TYPE Int64
Signed integer type (64bit)
Definition: Types.h:44
unsigned int UInt
Unsigned integer type.
Definition: Types.h:68
static bool extractDouble(IteratorT &begin, const IteratorT &end, double &target)
Definition: StringUtils.h:222
static String number(double d, UInt n)
Definition: StringUtils.h:191
static Int32 toInt32(const String &this_s)
Definition: StringUtils.h:201
static Int64 toInt64(const String &this_s)
Definition: StringUtils.h:206
static double toDouble(const String &this_s)
Definition: StringUtils.h:216
static float toFloat(const String &this_s)
Definition: StringUtils.h:211
static QString toQString(const String &this_s)
Definition: StringUtils.h:196
Main OpenMS namespace.
Definition: FeatureDeconvolution.h:22
static bool parse_nan(Iterator &first, Iterator const &last, Attribute &attr_)
Definition: StringUtils.h:151