Line data Source code
1 : /** \file stringUtils.cpp
2 : * \brief Implementation of utilities for working with strings
3 : *
4 : * \author Jared R. Males (jaredmales@gmail.com)
5 : *
6 : * \ingroup stringutils
7 : *
8 : */
9 :
10 : //***********************************************************************//
11 : // Copyright 2020 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 : #include "../../include/ioutils/stringUtils.hpp"
30 :
31 : namespace mx
32 : {
33 : namespace ioutils
34 : {
35 :
36 : // Specialization of convertToString to avoid converting a string to a string
37 : template <>
38 0 : std::string convertToString<std::string>( const std::string &value, int precision )
39 : {
40 : static_cast<void>( precision );
41 0 : return value;
42 : }
43 :
44 : namespace stoTImpl
45 : {
46 :
47 : template <typename typeT>
48 106 : typeT stoInt32s( const std::string &str, error_t *errc )
49 : {
50 : error_t _errc;
51 :
52 106 : long val = stoT( str, &_errc, meta::tagT<long>() );
53 :
54 106 : if( _errc == error_t::noerror )
55 : {
56 96 : if( val < std::numeric_limits<typeT>::lowest() )
57 : {
58 3 : _errc = error_t::erange;
59 3 : val = std::numeric_limits<typeT>::lowest();
60 : }
61 93 : else if( val > std::numeric_limits<typeT>::max() )
62 : {
63 5 : _errc = error_t::erange;
64 5 : val = std::numeric_limits<typeT>::max();
65 : }
66 : }
67 :
68 106 : if( errc )
69 : {
70 73 : *errc = _errc;
71 : }
72 :
73 106 : return static_cast<typeT>( val );
74 : }
75 :
76 8 : char stoT( const std::string &str, error_t *errc, meta::tagT<char> )
77 : {
78 8 : return stoInt32s<char>( str, errc );
79 : }
80 :
81 0 : signed char stoT( const std::string &str, error_t *errc, meta::tagT<signed char> )
82 : {
83 0 : return stoInt32s<signed char>( str, errc );
84 : }
85 :
86 5 : unsigned char stoT( const std::string &str, error_t *errc, meta::tagT<unsigned char> )
87 : {
88 5 : return stoInt32s<unsigned char>( str, errc );
89 : }
90 :
91 6 : short stoT( const std::string &str, error_t *errc, meta::tagT<short> )
92 : {
93 6 : return stoInt32s<short>( str, errc );
94 : }
95 :
96 5 : unsigned short stoT( const std::string &str, error_t *errc, meta::tagT<unsigned short> )
97 : {
98 5 : return stoInt32s<unsigned short>( str, errc );
99 : }
100 :
101 82 : int stoT( const std::string &str, error_t *errc, meta::tagT<int> )
102 : {
103 82 : return stoInt32s<int>( str, errc );
104 : }
105 :
106 5 : unsigned int stoT( const std::string &str, error_t *errc, meta::tagT<unsigned int> )
107 : {
108 : error_t _errc;
109 :
110 5 : unsigned long val = stoT( str, &_errc, meta::tagT<unsigned long>() );
111 :
112 5 : if( _errc == error_t::noerror )
113 : {
114 4 : if( val > std::numeric_limits<unsigned int>::max() )
115 : {
116 1 : _errc = error_t::erange;
117 1 : val = std::numeric_limits<unsigned int>::max();
118 : }
119 : }
120 :
121 5 : if( errc )
122 : {
123 4 : *errc = _errc;
124 : }
125 :
126 5 : return static_cast<unsigned int>( val );
127 : }
128 :
129 112 : long stoT( const std::string &str, error_t *errc, meta::tagT<long> )
130 : {
131 : error_t _errc;
132 :
133 : char *end;
134 :
135 112 : errno = 0;
136 :
137 112 : long val = std::strtol( str.c_str(), &end, 10 );
138 :
139 112 : if( errno != 0 )
140 : {
141 3 : _errc = errno2error_t( errno );
142 : }
143 109 : else if( end == str.c_str() )
144 : {
145 10 : _errc = error_t::invalidarg;
146 : }
147 : else
148 : {
149 99 : _errc = error_t::noerror;
150 : }
151 :
152 112 : if( errc )
153 : {
154 111 : *errc = _errc;
155 : }
156 :
157 112 : return val;
158 : }
159 :
160 10 : unsigned long stoT( const std::string &str, error_t *errc, meta::tagT<unsigned long> )
161 : {
162 : error_t _errc;
163 :
164 : char *end;
165 :
166 10 : errno = 0;
167 :
168 10 : unsigned long val = std::strtoul( str.c_str(), &end, 10 );
169 :
170 10 : if( errno != 0 )
171 : {
172 1 : _errc = errno2error_t( errno );
173 : }
174 9 : else if( end == str.c_str() )
175 : {
176 2 : _errc = error_t::invalidarg;
177 : }
178 : else
179 : {
180 7 : _errc = error_t::noerror;
181 : }
182 :
183 10 : if( errc )
184 : {
185 9 : *errc = _errc;
186 : }
187 :
188 10 : return val;
189 : }
190 :
191 9 : long long stoT( const std::string &str, error_t *errc, meta::tagT<long long> )
192 : {
193 : error_t _errc;
194 :
195 : char *end;
196 :
197 9 : errno = 0;
198 :
199 9 : long long val = std::strtoll( str.c_str(), &end, 10 );
200 :
201 9 : if( errno != 0 )
202 : {
203 2 : _errc = errno2error_t( errno );
204 : }
205 7 : else if( end == str.c_str() )
206 : {
207 2 : _errc = error_t::invalidarg;
208 : }
209 : else
210 : {
211 5 : _errc = error_t::noerror;
212 : }
213 :
214 9 : if( errc )
215 : {
216 8 : *errc = _errc;
217 : }
218 :
219 9 : return val;
220 : }
221 :
222 5 : unsigned long long stoT( const std::string &str, error_t *errc, meta::tagT<unsigned long long> )
223 : {
224 : error_t _errc;
225 :
226 : char *end;
227 :
228 5 : errno = 0;
229 :
230 5 : unsigned long long val = std::strtoull( str.c_str(), &end, 10 );
231 :
232 5 : if( errno != 0 )
233 : {
234 1 : _errc = errno2error_t( errno );
235 : }
236 4 : else if( end == str.c_str() )
237 : {
238 1 : _errc = error_t::invalidarg;
239 : }
240 : else
241 : {
242 3 : _errc = error_t::noerror;
243 : }
244 :
245 5 : if( errc )
246 : {
247 4 : *errc = _errc;
248 : }
249 :
250 5 : return val;
251 : }
252 :
253 : /* bool specialization
254 : * First looks for 0/1, f/t, or F/T in the first non-space character of str.
255 : * Otherwise, uses long long and casts to bool.
256 : *
257 : * returns the converted numerical value.
258 : */
259 34 : bool stoT( const std::string &str, error_t *errc, meta::tagT<bool> )
260 : {
261 34 : char c = str[0];
262 34 : size_t i = 0;
263 36 : while( i < str.length()-1 && isspace( c ) )
264 : {
265 2 : ++i;
266 2 : c = str[i];
267 : }
268 :
269 34 : if( c == '0' || c == 'f' || c == 'F' )
270 : {
271 13 : if(errc)
272 : {
273 3 : *errc = error_t::noerror;
274 : }
275 :
276 13 : return false;
277 : }
278 21 : else if( c == '1' || c == 't' || c == 'T' )
279 : {
280 18 : if(errc)
281 : {
282 3 : *errc = error_t::noerror;
283 : }
284 :
285 18 : return true;
286 : }
287 :
288 3 : return static_cast<bool>( stoT( str, errc, meta::tagT<long long>() ) );
289 : }
290 :
291 67 : float stoT( const std::string &str, error_t *errc, meta::tagT<float> )
292 : {
293 : error_t _errc;
294 :
295 : char *end;
296 :
297 67 : errno = 0;
298 :
299 67 : float val = std::strtof( str.c_str(), &end );
300 :
301 67 : if( errno != 0 )
302 : {
303 2 : _errc = errno2error_t( errno );
304 : }
305 65 : else if( end == str.c_str() )
306 : {
307 2 : _errc = error_t::invalidarg;
308 : }
309 : else
310 : {
311 63 : _errc = error_t::noerror;
312 : }
313 :
314 67 : if( errc )
315 : {
316 50 : *errc = _errc;
317 : }
318 :
319 67 : return val;
320 : }
321 :
322 97 : double stoT( const std::string &str, error_t *errc, meta::tagT<double> )
323 : {
324 : error_t _errc;
325 :
326 : char *end;
327 :
328 97 : errno = 0;
329 :
330 97 : double val = std::strtod( str.c_str(), &end );
331 :
332 97 : if( errno != 0 )
333 : {
334 2 : _errc = errno2error_t( errno );
335 : }
336 95 : else if( end == str.c_str() )
337 : {
338 2 : _errc = error_t::invalidarg;
339 : }
340 : else
341 : {
342 93 : _errc = error_t::noerror;
343 : }
344 :
345 97 : if( errc )
346 : {
347 11 : *errc = _errc;
348 : }
349 :
350 97 : return val;
351 : }
352 :
353 5 : long double stoT( const std::string &str, error_t *errc, meta::tagT<long double> )
354 : {
355 : error_t _errc;
356 :
357 : char *end;
358 :
359 5 : errno = 0;
360 :
361 5 : long double val = std::strtold( str.c_str(), &end );
362 :
363 5 : if( errno != 0 )
364 : {
365 2 : _errc = errno2error_t( errno );
366 : }
367 3 : else if( end == str.c_str() )
368 : {
369 1 : _errc = error_t::invalidarg;
370 : }
371 : else
372 : {
373 2 : _errc = error_t::noerror;
374 : }
375 :
376 5 : if( errc )
377 : {
378 4 : *errc = _errc;
379 : }
380 :
381 5 : return val;
382 : }
383 :
384 : #ifdef HAS_QUAD
385 0 : __float128 stoT( const std::string &str, error_t *errc, meta::tagT<__float128> )
386 : {
387 : error_t _errc;
388 :
389 : char *end;
390 :
391 0 : errno = 0;
392 :
393 0 : __float128 val = ::strtof128( str.c_str(), &end );
394 :
395 0 : if( errno != 0 )
396 : {
397 0 : _errc = errno2error_t( errno );
398 : }
399 0 : else if( end == str.c_str() )
400 : {
401 0 : _errc = error_t::invalidarg;
402 : }
403 : else
404 : {
405 0 : _errc = error_t::noerror;
406 : }
407 :
408 0 : if( errc )
409 : {
410 0 : *errc = _errc;
411 : }
412 :
413 0 : return val;
414 : }
415 :
416 : #endif // has_quad
417 :
418 114 : std::string stoT( const std::string &str, error_t *errc, meta::tagT<std::string> )
419 : {
420 114 : if(errc)
421 : {
422 22 : *errc = mx::error_t::noerror;
423 : }
424 :
425 114 : return str;
426 : }
427 :
428 : } // namespace stoTImpl
429 :
430 : // Convert a string to all lower case.
431 0 : mx::error_t toLower( std::string &outstr, const std::string &instr )
432 : {
433 : try
434 : {
435 0 : outstr.resize( instr.size() );
436 : }
437 0 : catch( const std::length_error &e )
438 : {
439 0 : return mx::error_t::std_length_error;
440 0 : }
441 0 : catch( const std::bad_alloc &e )
442 : {
443 0 : return mx::error_t::std_bad_alloc;
444 0 : }
445 0 : catch( const std::exception &e )
446 : {
447 0 : return mx::error_t::std_exception;
448 0 : }
449 0 : catch( ... )
450 : {
451 0 : return mx::error_t::exception;
452 0 : }
453 :
454 0 : for( size_t i = 0; i < instr.size(); ++i )
455 : {
456 0 : outstr[i] = tolower( instr[i] );
457 : }
458 :
459 0 : return mx::error_t::noerror;
460 : }
461 :
462 : // Convert a string to all lower case.
463 0 : std::string toLower( const std::string &instr, mx::error_t *errc )
464 : {
465 0 : std::string outstr;
466 :
467 0 : mx::error_t _errc = toLower( outstr, instr );
468 :
469 0 : if( errc )
470 : {
471 0 : *errc = _errc;
472 : }
473 :
474 0 : return outstr;
475 0 : }
476 :
477 : // Convert a string to all upper case.
478 0 : mx::error_t toUpper( std::string &outstr, const std::string &instr )
479 : {
480 : try
481 : {
482 0 : outstr.resize( instr.size() );
483 : }
484 0 : catch( const std::length_error &e )
485 : {
486 0 : return mx::error_t::std_length_error;
487 0 : }
488 0 : catch( const std::bad_alloc &e )
489 : {
490 0 : return mx::error_t::std_bad_alloc;
491 0 : }
492 0 : catch( const std::exception &e )
493 : {
494 0 : return mx::error_t::std_exception;
495 0 : }
496 0 : catch( ... )
497 : {
498 0 : return mx::error_t::exception;
499 0 : }
500 :
501 0 : for( size_t i = 0; i < instr.size(); ++i )
502 : {
503 0 : outstr[i] = toupper( instr[i] );
504 : }
505 :
506 0 : return mx::error_t::noerror;
507 : }
508 :
509 : // Convert a string to all upper case.
510 0 : std::string toUpper( const std::string &instr, mx::error_t *errc )
511 : {
512 0 : std::string outstr;
513 :
514 0 : mx::error_t _errc = toUpper( outstr, instr );
515 :
516 0 : if( errc )
517 : {
518 0 : *errc = _errc;
519 : }
520 :
521 0 : return outstr;
522 0 : }
523 :
524 : // Remove all white space from a string.
525 0 : void removeWhiteSpace( std::string &outstr, const std::string &instr )
526 : {
527 0 : outstr = instr;
528 :
529 0 : outstr.erase( std::remove_if( outstr.begin(), outstr.end(), ::isspace ), outstr.end() );
530 0 : }
531 :
532 : // Remove all white space from a string.
533 0 : std::string removeWhiteSpace( const std::string &instr )
534 : {
535 0 : std::string outstr;
536 :
537 0 : removeWhiteSpace( outstr, instr );
538 :
539 0 : return outstr;
540 0 : }
541 :
542 : // Wrap a string by breaking it into smaller sized portions of a desired width
543 14 : int stringWrap( std::vector<std::string> &lines, const std::string &str, int width )
544 : {
545 14 : int L = str.length();
546 :
547 14 : if( L == 0 )
548 1 : return 0;
549 : int startPos, tmpPos, endPos;
550 :
551 13 : bool done = false;
552 :
553 13 : startPos = 0;
554 :
555 26 : while( !done )
556 : {
557 13 : if( startPos == L )
558 0 : --startPos; // Just to make sure
559 :
560 13 : endPos = startPos + width;
561 :
562 13 : if( endPos >= L )
563 : {
564 13 : lines.push_back( str.substr( startPos, L - startPos ) );
565 13 : done = true;
566 : }
567 : else
568 : {
569 : // Backup to nearest space
570 0 : tmpPos = endPos;
571 0 : while( !isspace( str[tmpPos] ) && tmpPos >= startPos )
572 0 : --tmpPos;
573 :
574 : // If we aren't at the beginning (i.e. splitting consecutive characters) we use new end position
575 0 : if( tmpPos > startPos )
576 0 : endPos = tmpPos;
577 :
578 0 : lines.push_back( str.substr( startPos, endPos - startPos ) );
579 :
580 0 : startPos = endPos;
581 :
582 : // Clear 1 space
583 0 : if( str[startPos] == ' ' )
584 0 : ++startPos;
585 : }
586 : }
587 :
588 13 : return 0;
589 : }
590 :
591 : } // namespace ioutils
592 : } // namespace mx
|