Line data Source code
1 : /** \file stringUtils.hpp
2 : * \brief Utilities for working with strings
3 : *
4 : * \author Jared R. Males (jaredmales@gmail.com)
5 : *
6 : * \ingroup stringutils
7 : *
8 : */
9 :
10 : //***********************************************************************//
11 : // Copyright 2015, 2016, 2017 Jared R. Males (jaredmales@gmail.com)
12 : //
13 : // This file is part of mxlib.
14 : //
15 : // mxlib is free software: you can redistribute it and/or modify
16 : // it under the terms of the GNU General Public License as published by
17 : // the Free Software Foundation, either version 3 of the License, or
18 : // (at your option) any later version.
19 : //
20 : // mxlib is distributed in the hope that it will be useful,
21 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
22 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 : // GNU General Public License for more details.
24 : //
25 : // You should have received a copy of the GNU General Public License
26 : // along with mxlib. If not, see <http://www.gnu.org/licenses/>.
27 : //***********************************************************************//
28 :
29 : #ifndef ioutils_stringUtils_hpp
30 : #define ioutils_stringUtils_hpp
31 :
32 : #include <string>
33 : #include <sstream>
34 : #include <vector>
35 : #include <limits>
36 : #include <algorithm>
37 :
38 : #include "../meta/tagT.hpp"
39 : #include "../mxlib.hpp"
40 :
41 : namespace mx
42 : {
43 : namespace ioutils
44 : {
45 :
46 : /** \addtogroup stringutils
47 : * @{
48 : */
49 :
50 : /// Convert a numerical value to a string
51 : /** The default version uses the stream library to convert. A specialization is provided to prevent conversion of
52 : std::string.
53 : *
54 : * The precision parameter is only used for floating point types. If the default precision==0 is passed, then the
55 : maximum useful precision is
56 : * used, from the value of std::numeric_limits\<typeT\>::max_digits10.
57 : *
58 : * The width and pad template parameters can be used to set a fixed maximum width and a pad character.
59 : *
60 : * Examples:
61 : *
62 : * To convert a double precision number to string:
63 : * \code
64 : double d = 2.898434;
65 : std::string str;
66 : str = convertToString(d); //note that you will not normally need to specify <typeT>
67 : * \endcode
68 : *
69 : * To produce a fixed width 0 padded string from an integer:
70 : * \code
71 : int i = 23;
72 : std::string str;
73 : str = convertToString<int, 5, '0'>(i); //result is "00023".
74 : * \endcode
75 : *
76 : * \tparam typeT is the type of value to convert
77 : * \tparam width specifies the maximum width, not including the '\0'
78 : * \tparam pad specifies the pad character
79 : *
80 : * \returns a string representation of value
81 : *
82 : */
83 : template <typename typeT, unsigned width = 0, char pad = ' '>
84 : [[deprecated( "Use std::format instead" )]]
85 : std::string convertToString(
86 : const typeT &value, ///< [in] the value of type typeT to be converted
87 : int precision = 0 ///< [in] [optional] the precision (see
88 : ///< http://www.cplusplus.com/reference/ios/ios_base/precision/) to use for floating point types.
89 : )
90 : {
91 :
92 : std::ostringstream convert;
93 :
94 : if( std::is_floating_point<typeT>::value )
95 : {
96 : if( precision == 0 )
97 : {
98 : convert.precision( std::numeric_limits<typeT>::max_digits10 );
99 : }
100 : else
101 : {
102 : convert.precision( precision );
103 : }
104 : }
105 :
106 : convert << value;
107 :
108 : if( width == 0 )
109 : {
110 : return convert.str();
111 : }
112 : else
113 : {
114 : std::string c = convert.str();
115 :
116 : if( c.length() > width )
117 : {
118 : c.erase( width, c.length() - width );
119 : return c;
120 : }
121 :
122 : return std::string( width - c.length(), pad ) + c;
123 : }
124 : }
125 :
126 : // Specialization of convertToString to avoid converting a string to a string
127 : template <>
128 : std::string convertToString<std::string>( const std::string &value, int precision );
129 :
130 : namespace stoTImpl
131 : {
132 : // tag overloads for stoT
133 :
134 : char stoT( const std::string &str, error_t *errc, meta::tagT<char> );
135 : signed char stoT( const std::string &str, error_t *errc, meta::tagT<signed char> );
136 : unsigned char stoT( const std::string &str, error_t *errc, meta::tagT<unsigned char> );
137 : short stoT( const std::string &str, error_t *errc, meta::tagT<short> );
138 : unsigned short stoT( const std::string &str, error_t *errc, meta::tagT<unsigned short> );
139 : int stoT( const std::string &str, error_t *errc, meta::tagT<int> );
140 : unsigned int stoT( const std::string &str, error_t *errc, meta::tagT<unsigned int> );
141 : long stoT( const std::string &str, error_t *errc, meta::tagT<long> );
142 : unsigned long stoT( const std::string &str, error_t *errc, meta::tagT<unsigned long> );
143 : long long stoT( const std::string &str, error_t *errc, meta::tagT<long long> );
144 : unsigned long long stoT( const std::string &str, error_t *errc, meta::tagT<unsigned long long> );
145 : bool stoT( const std::string &str, error_t *errc, meta::tagT<bool> );
146 : float stoT( const std::string &str, error_t *errc, meta::tagT<float> );
147 : double stoT( const std::string &str, error_t *errc, meta::tagT<double> );
148 : long double stoT( const std::string &str, error_t *errc, meta::tagT<long double> );
149 :
150 : std::string stoT( const std::string &str, error_t *errc, meta::tagT<std::string> );
151 :
152 : #ifdef HAS_QUAD
153 : __float128 stoT( const std::string &str, error_t *errc, meta::tagT<__float128> );
154 : #endif
155 :
156 : } // namespace stoTImpl
157 :
158 : /// Convert a string to a numerical value.
159 : /** Provides exception-less string conversion.
160 : *
161 : * Example:
162 : * \code
163 : * std::string str = "2.34567";
164 : * mx::error_t errc;
165 : * double d;
166 : * d = stoT<double>(str, &errc);
167 : * if(errc != mx::error_t::noerror)
168 : * {
169 : * //do something
170 : * }
171 : * \endcode
172 : *
173 : * Values of `typeT=bool` are converted from strings that start with 0/f/F an 1/t/T as false and
174 : * true respectively. If that fails the string is converted to long long and then to bool, so if it is
175 : * a valid number that fits in long long, it will evaluate to true or false based on whether or not it is 0.
176 : *
177 : * Complex types (`std::complex<realT>`) are not supported.
178 : *
179 : * \tparam typeT is the type of the numerical value desired
180 : *
181 : * \returns the converted numerical value.
182 : *
183 : * \b Error \b Codes
184 : * - mx::error_t::noerror on success
185 : * - mx::error_t::erange for an out of range value for typeT
186 : * - mx::error_t::invalidarg for a string that can't be converted
187 : */
188 : template <typename typeT>
189 12 : typeT stoT( const std::string &str, /**< [in] the string to convert*/
190 : error_t *errc = nullptr /**< [out] [optional] pointer to an mxlib error code set during the conversion */
191 : )
192 : {
193 12 : return stoTImpl::stoT( str, errc, meta::tagT<typeT>() );
194 : }
195 :
196 : /// Convert a string to a numerical value.
197 : /** Provides exception-less string conversion.
198 : *
199 : * \overload
200 : *
201 : * \tparam typeT is the type of the numerical value desired
202 : *
203 : * \returns the converted numerical value.
204 : *
205 : * \b Error \b Codes
206 : * - mx::error_t::noerror on success
207 : * - mx::error_t::erange for an out of range value for typeT
208 : * - mx::error_t::invalidarg for a string that can't be converted
209 : */
210 : template <typename typeT>
211 : typeT stoT( const std::string &str, /**< [in] the string to convert*/
212 : error_t &errc /**< [out] [optional] mxlib error code set during the conversion */
213 : )
214 : {
215 : return stoTImpl::stoT( str, &errc, meta::tagT<typeT>() );
216 : }
217 :
218 : /// Convert a string to a numerical value.
219 : /** see \ref stoT
220 : *
221 : * \deprecated
222 : */
223 : template <typename typeT>
224 : [[deprecated( "Use mx::ioutils::stoT<typeT> instead" )]]
225 : typeT convertFromString( const std::string &str, /**< [in] the string to convert*/
226 : error_t *errc = nullptr /**< [out] [optional] mxlib error code */ )
227 : {
228 : // If no specialization exists, we try to cast
229 : return stoT<typeT>( str, errc );
230 : }
231 :
232 : /// Convert a string to all lower case.
233 : /** Calls the c tolower function for each character in \p instr.
234 : *
235 : * \returns mx::error_t::noerror on success
236 : * \returns mx::error_t::std_length_error if string::resize throws a length error
237 : * \returns mx::error_t::std_bad_alloc if string::resize throws a bad alloc
238 : * \returns mx::error_t::std_exception if string::resize throws a std::exception
239 : * \returns mx::error_t::exception if string::resize throws any other exception
240 : */
241 : mx::error_t toLower( std::string &outstr, ///< [out] will be resized and populated with the lower case characters
242 : const std::string &instr ///< [in] is the string to convert
243 : );
244 :
245 : /// Convert a string to all lower case.
246 : /** Calls the c tolower function for each character in \p instr.
247 : *
248 : * \return the all lower case string
249 : *
250 : * \b Errors
251 : * - mx::error_t::noerror on success
252 : * - mx::error_t::std_length_error if string::resize throws a length error
253 : * - mx::error_t::std_bad_alloc if string::resize throws a bad alloc
254 : * - mx::error_t::std_exception if string::resize throws a std::exception
255 : * - mx::error_t::exception if string::resize throws any other exception
256 : *
257 : */
258 : std::string toLower( const std::string &instr, /**< [in] is the string to convert*/
259 : mx::error_t *errc = nullptr /**< [out] [optional] the error code indicating success or error */ );
260 :
261 : /// Convert a string to all upper case.
262 : /** Calls the c toupper function for each character in \p instr.
263 : *
264 : * \returns mx::error_t::noerror on success
265 : * \returns mx::error_t::std_length_error if string::resize throws a length error
266 : * \returns mx::error_t::std_bad_alloc if string::resize throws a bad alloc
267 : * \returns mx::error_t::std_exception if string::resize throws a std::exception
268 : * \returns mx::error_t::exception if string::resize throws any other exception
269 : */
270 : mx::error_t toUpper( std::string &outstr, ///< [out] will be resized and populated with the lower case characters
271 : const std::string &instr ///< [in] is the string to convert
272 : );
273 :
274 : /// Convert a string to all upper case.
275 : /** Calls the c toupper function for each character in \p instr.
276 : *
277 : * \returns the all upper case string
278 : *
279 : * \b Errors
280 : * - mx::error_t::noerror on success
281 : * - mx::error_t::std_length_error if string::resize throws a length error
282 : * - mx::error_t::std_bad_alloc if string::resize throws a bad alloc
283 : * - mx::error_t::std_exception if string::resize throws a std::exception
284 : * - mx::error_t::exception if string::resize throws any other exception
285 : */
286 : std::string toUpper( const std::string &instr, /**< [in] is the string to convert*/
287 : mx::error_t *errc = nullptr /**< [out] [optional] the error code indicating success or error */ );
288 :
289 : /// Remove all white space from a string.
290 : /**
291 : * Uses std::remove_if.
292 : */
293 : void removeWhiteSpace( std::string &outstr, ///< [out] will contain the new string with no whitespace.
294 : const std::string &instr ///< [in] is the string to remove whitespace from
295 : );
296 :
297 : /// Remove all white space from a string.
298 : /**
299 : * Uses std::remove_if.
300 : *
301 : * \returns the modified string.
302 : */
303 : std::string removeWhiteSpace( const std::string &instr /**< [in] is the string to remove whitespace from*/ );
304 :
305 : /// Wrap a string by breaking it into smaller sized portions of a desired width
306 : /** Whenever possible breaks at spaces. A single space is discarded at the break.
307 : */
308 : int stringWrap( std::vector<std::string> &lines, /**< [out] each new entry contains a wrapped portion of the string.
309 : Not cleared, so can accumulate. */
310 : const std::string &str, ///< [in] the string to wrap
311 : int width ///< [in] the maximum width of the output strings
312 : );
313 :
314 : /// Parses a string into a vector of tokens delimited by a character
315 : /** E.g., the string
316 : * \code
317 : std::string s={"0,1,2,3,4"};
318 : std::vector<int> v;
319 : parseStringVector(v,s);
320 : \endcode
321 : * is parsed to a vector as if it was initialized with
322 : \code
323 : std::vector<int> v = {0,1,2,3,4};
324 : \endcode
325 : *
326 : * \tparam typeT the type to convert the tokens too.
327 : */
328 : template <typename typeT>
329 : void parseStringVector(
330 : std::vector<typeT> &v, ///< [out] the vector holding the parsed and converted tokens. Is cleared.
331 : const std::string &s, ///< [in] the string to parse
332 : char delim = ',' ///< [in] [optional] the delimiter. Default is comma \p ','.
333 : )
334 : {
335 : size_t st;
336 : size_t com;
337 :
338 : st = 0;
339 : com = s.find( delim, st );
340 :
341 : v.clear();
342 :
343 : while( com != std::string::npos )
344 : {
345 : v.push_back( convertFromString<typeT>( s.substr( st, com - st ) ) );
346 : st = com + 1;
347 : com = s.find( delim, st );
348 : }
349 : v.push_back( convertFromString<typeT>( s.substr( st, s.size() - st ) ) );
350 : }
351 :
352 : /// Parses a string into a vector of tokens delimited by a set of characters
353 : /** E.g., the string
354 : * \code
355 : std::string s={"0,1:2 3,4"};
356 : std::vector<int> v;
357 : parseStringVector(v, s, ",: ");
358 : \endcode
359 : * is parsed to a vector as if it was initialized with
360 : \code
361 : std::vector<int> v = {0,1,2,3,4};
362 : \endcode
363 : *
364 : * \tparam typeT the type to convert the tokens too.
365 : */
366 : template <typename typeT>
367 : void parseStringVector(
368 : std::vector<typeT> &v, ///< [out] the vector holding the parsed and converted tokens. Is cleared.
369 : const std::string &s, ///< [in] the string to parse
370 : const std::string &delims ///< [in] the delimiters.
371 : )
372 : {
373 : size_t st;
374 : size_t com;
375 :
376 : st = 0;
377 : com = s.find_first_of( delims, st );
378 :
379 : v.clear();
380 :
381 : while( com != std::string::npos )
382 : {
383 : v.push_back( convertFromString<typeT>( s.substr( st, com - st ) ) );
384 : st = com + 1;
385 : com = s.find_first_of( delims, st );
386 : }
387 : v.push_back( convertFromString<typeT>( s.substr( st, s.size() - st ) ) );
388 : }
389 : /// @}
390 :
391 : } // namespace ioutils
392 : } // namespace mx
393 :
394 : #endif // ioutils_stringUtils_hpp
|