Loading...
Searching...
No Matches
StringTools.h
1/*
2
3MIT License
4
5Copyright (c) 2017 FMI Open Development / Markus Peura, first.last@fmi.fi
6
7Permission is hereby granted, free of charge, to any person obtaining a copy
8of this software and associated documentation files (the "Software"), to deal
9in the Software without restriction, including without limitation the rights
10to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11copies of the Software, and to permit persons to whom the Software is
12furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in all
15copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23SOFTWARE.
24
25*/
26/*
27Part of Rack development has been done in the BALTRAD projects part-financed
28by the European Union (European Regional Development Fund and European
29Neighbourhood Partnership Instrument, Baltic Sea Region Programme 2007-2013)
30*/
31/*
32 * StringTools.h
33 *
34 * Created on: Jul 21, 2010
35 * Author: mpeura
36 */
37
38#ifndef DRAIN_STRING_H_
39#define DRAIN_STRING_H_
40
41#include <limits>
42#include <iterator>
43#include <string>
44#include <sstream>
45#include <iostream>
46#include <list>
47#include <map>
48
49
50namespace drain {
51
52template <typename T>
54public:
55
56
57 void convertToString(const T & value, std::string &s){
58 std::stringstream sstr;
59 sstr << value;
60 s.assign(sstr.str());
61 };
62
63 void convertFromString(const std::string &s, T & value){
64 std::stringstream sstr(s);
65 sstr >> value;
66 };
67
68
69};
70
71template <typename T=std::string>
72class StringWrapper : public std::string, protected StringConverter<T> {
73
74public:
75
76 inline
77 //StringWrapper(const std::string & s="") : std::string(s){};
78 //StringWrapper() : std::string(){};
80 //set("");
81 };
82
84 //template <typename T>
85 inline
86 StringWrapper(const T & x){
87 set(x);
88 };
89
90
91 inline
92 void set(const std::string & s=""){
93 std::string::assign(s);
94 };
95
96 inline
97 void set(const StringWrapper & e){
98 std::string::assign(e);
99 };
100
101 inline
102 void set(const char *s){
103 std::string::assign(s);
104 };
105
106
108
114 template <typename T2>
115 inline
116 void set(const T2 & x){
117 // setSpecial(x);
119 //StringConverter<T>::convertToString(x, *this);
120 };
121
130};
131
132
134
135public:
136
137 static
138 bool startsWith(const std::string &s, const std::string & substring);
139
140
141 static
142 bool endsWith(const std::string &s, const std::string & substring);
143
144
146
148 static
149 std::string & upperCase(std::string & s, size_t n = std::numeric_limits<size_t>::max());
150
152
154 static
155 char upperCase(char c);
156
158
161 static
162 std::string & lowerCase(std::string & s, size_t n = std::numeric_limits<size_t>::max());
163
165
167 static
168 char lowerCase(char c);
169
170
171
173
176 static
177 void replace(const std::string &src, char search, char repl, std::ostream & ostr);
178
180
183 static
184 void replace(const std::string &src, char from, char repl, std::string &dst);
185
187
190 template <typename S, typename R>
191 static
192 void replace(const std::string &src, const S & search, const R & repl, std::ostream & ostr){
193
194 const size_t length = getLength(search);
195 std::string::size_type i = 0;
196 std::string::size_type pos;
197
198 while (true) {
199 pos = src.find(search, i);
200 if (pos == std::string::npos){
201 ostr << src.substr(i);
202 return;
203 }
204
205 // String was found
206 ostr << src.substr(i, pos-i) << repl;
207
208 // Jump over <search>: move forward len(search) chars
209 i = pos + length;
210 }
211 }
212
213
215
218 template <typename T1, typename T2>
219 static inline
220 void replace(const std::string &src, const T1 &search, const T2 & repl, std::string & dst){
221 std::stringstream result;
222 replace(src, search, repl, result);
223 dst = result.str();
224 }
225
226
228
234 /*
235 template <typename T1, typename T2>
236 static inline
237 std::string replace(const std::string &src, const T1 & search, const T2 & repl){
238 std::string dst;
239 replace(src, search, repl, dst);
240 return dst;
241 }
242 */
243
244 // MAP VERSIONS
245
247 template <typename T>
248 static
249 void replace(const std::string & src, const std::map<char,T> & m, std::ostream & ostr){
250 typename std::map<char,T>::const_iterator it;
251 for (char c: src){
252 it = m.find(c);
253 if (it == m.end()){
254 ostr << c;
255 }
256 else {
257 ostr << it->second;
258 }
259 }
260 };
261
262 template <typename T>
263 static inline
264 void replace(const std::string & src, const std::map<char,T> & m, std::string & dst){
265 std::stringstream result;
266 replace(src, m, result);
267 dst = result.str();
268 }
269
271
274 static
275 void replace(const std::string & src, const std::map<char,char> & m, std::string & dst);
276
282 template <class K, class V>
283 static inline
284 void replace(const std::string & src, const std::map<K,V> & m, std::string & dst){
285 replaceWithMap(src, m, dst);
286 };
287
288 template <class K, class V>
289 static inline
290 void replace(const std::string & src, const std::initializer_list<std::pair<K,V> > & m, std::string & dst){
291 replaceWithMap(src, m, dst);
292 };
293
295 static
296 std::string & convertEscaped(std::string &s);
297
298
299private:
300
301 static inline
302 size_t getLength(char c){
303 return 1;
304 };
305
306 static inline
307 size_t getLength(const std::string & s){
308 return s.length();
309 };
310
311 template <class M>
312 static inline
313 void replaceWithMap(const std::string & src, const M & m, std::string & dst){
314
315 if (m.empty()){
316 // Replace nothing in src, hence assign it directly to result.
317 if (&dst != &src){
318 dst = src; // clumsy?
319 }
320 return;
321 }
322
323 for (const auto & entry: m){
324 // std::cerr << "replacing " << entry.first << " -> " << entry.second << " in " << dst << std::endl;
325 replace(dst, entry.first, entry.second, dst);
326 }
327 };
328
329
330public:
331
332
333
335 static
336 std::string trim(const std::string &s, const std::string &trimChars=" \t\n\r");
337
339
346 static
347 std::string trimSymmetric(const std::string &s, const std::string &leading= "'\"", const std::string & trailing="");
348
349
351
362 static
363 bool trimScan(const std::string &s, size_t & pos1, size_t & pos2, const std::string &trimChars=" \t\n");
364
366
379 template <class T, class C>
380 static
381 void split(const std::string & s, T & sequence, const C &separators, const std::string & trimChars=" \t\n");
382
384 /*
385 template <class T>
386 static inline
387 void split(const std::string & s, T & sequence, char separator=',', const std::string & trimChars=" \t\n"){
388 StringTools::split(s, sequence, std::string(1,separator), trimChars);
389 }
390 */
391
393
408 template <class T1, class T2, class C>
409 static
410 bool split2(const std::string & s, T1 & first, T2 & second, const C &separators, const std::string & trimChars=" \t\n");
411
413
419 static
420 size_t extractPrefixLength(const std::string & src1, const std::string & src2, size_t step = 1);
421
423
431 static
432 size_t extractPrefix(const std::string & src1, const std::string & src2,
433 std::string & prefix, std::string & dst1, std::string & dst2, size_t step = 1);
434
436
442 static inline
443 size_t extractPrefix(std::string & s1, std::string & s2, std::string & prefix, size_t step = 1){
444 return extractPrefix(s1, s2, prefix, s1, s2, step);
445 }
446
447
449
452 template <class T>
453 static
454 std::ostream & join(const T & container, std::ostream & ostr, char separator = 0){
455 char sep = 0;
456 for (typename T::const_iterator it = container.begin(); it != container.end(); ++it){
457 if (sep)
458 ostr << sep;
459 ostr << *it;
460 sep = separator;
461 }
462 return ostr;
463 }
464
466
469 template <class T>
470 static inline
471 std::string join(T & container, char separator = 0){
472 std::stringstream sstr;
473 StringTools::join(container, sstr, separator);
474 return sstr.str();
475 }
476
478 template <unsigned int S>
479 static
480 void read(std::istream &istr, std::string & s){
481 char buffer[S];
482 while (istr.read(buffer, S)){
483 s.append(buffer, S);
484 }
485 s.append(buffer, istr.gcount());
486 }
487
488
490
498 template <class T>
499 static
500 void convert(const std::string &s, T & dst);
501
503
509 template <class T>
510 static
511 T convert(const std::string &s);
512
513
514 template <class T>
515 static
516 std::string & import(const T & src, std::string & target);
517
518
519
520
521//private: CONSIDER!
522
524
534 template <class T>
535 static
536 const T & lazyConvert(const std::string &s, T & tmp);
537
538private:
539
540 template <class T>
541 static
542 void appendString(T & sequence, const std::string & str){
543 typename T::value_type tmp;
544 sequence.insert(sequence.end(), StringTools::lazyConvert(str, tmp));
545 }
546
547 template <class T>
548 static
549 void appendSubstring(T & sequence, const std::string & str, std::string::size_type pos, std::string::size_type n){
550
551 if (n > 0){
552 appendString(sequence, str.substr(pos, n));
553 }
554 else {
555 appendString(sequence, "");
556 }
557
558 }
559
560};
561
562
563template <class T, class C>
564void StringTools::split(const std::string & str, T & sequence, const C & separators, const std::string & trimChars){
565
566 sequence.clear();
567
568 const bool TRIM = !trimChars.empty();
569 const std::string::size_type n = str.size();
570
571 std::string::size_type pos1 = 0; // Start of segment
572 std::string::size_type pos2 = n; // std::string::npos; // End of segment (index of last char + 1)
573
574 if (false){ //separators.empty()){ // = no split! :-)
575
576 if (TRIM){
577 StringTools::trimScan(str, pos1, pos2, trimChars);
578 appendSubstring(sequence, str, pos1, pos2-pos1);
579 }
580 else
581 appendString(sequence, str);
582
583 return;
584 }
585 else {
586
587 // Index of the next separator position
588 std::string::size_type pos = pos1; // "irreversible"
589
590 while (true) {
591
592 pos1 = pos;
593 pos = str.find_first_of(separators, pos);
594 if (pos == std::string::npos){
595 pos2 = n;
596 if (TRIM)
597 StringTools::trimScan(str, pos1, pos2, trimChars);
598 appendSubstring(sequence, str, pos1, pos2-pos1);
599 return;
600 }
601 else {
602 pos2 = pos;
603 if (TRIM)
604 StringTools::trimScan(str, pos1, pos2, trimChars);
605 appendSubstring(sequence, str, pos1, pos2-pos1);
606 pos = str.find_first_not_of(trimChars, pos+1); // if separator is space, or other also in trimChars
607 //pos = str.find_last_not_of(trimChars, pos);
608 //++pos; // for the next round
609 }
610
611 }
612 }
613}
614
615/*
616template <>
617bool StringTools::split2(const std::string & s, std::string & first, std::string & second, const char *separators, const std::string & trimChars);
618*/
619
620template <class T1, class T2, class S>
621bool StringTools::split2(const std::string & s, T1 & first, T2 & second, const S & separators, const std::string & trimChars){
622
623 std::size_t i = s.find_first_of(separators);
624
625 if (i != std::string::npos){ // input of type "key=value" found
626
627 std::string srcFirst(s, 0, i);
628 ++i;
629 std::string srcSecond(s, std::min(s.size(), i));
630
631 if (!trimChars.empty()){
632 first = lazyConvert(StringTools::trim(srcFirst, trimChars), first); // first=first should not clear the object!
633 }
634 else {
635 first = lazyConvert(srcFirst, first); // Note: first=first should not clear the object!
636 }
637
638 if (!srcSecond.empty()){
639 if (!trimChars.empty()){
640 second = lazyConvert(StringTools::trim(srcSecond), second);
641 }
642 else {
643 second = lazyConvert(srcSecond, second);
644 }
645 }
646
647 /*
648 ++i;
649 if (i<s.size()){
650 //std::cerr << "toka " << s.substr(i) << '\n';
651 if (!trimChars.empty()){
652 // sstr2 << StringTools::trim(s.substr(i), trimChars);
653 // sstr2 >> second;
654 second = lazyConvert(StringTools::trim(s.substr(i), trimChars), second);
655 }
656 else {
657 // sstr2 << s.substr(i);
658 // sstr2 >> second;
659 second = lazyConvert(s.substr(i), second);
660 }
661 }
662 */
663 return true;
664 }
665 else {
666 // std::stringstream sstr;
667 if (trimChars.empty()){
668 //sstr << s;
669 //sstr >> first;
670 first = lazyConvert(s, first);
671 }
672 else {
673 // sstr << StringTools::trim(s, trimChars);
674 // sstr >> first;
675 first = lazyConvert(StringTools::trim(s, trimChars), first);
676 }
677 return false;
678 }
679
680
681}
682
683
684
685
686
687
688
689template <>
690inline
691const std::string & StringTools::lazyConvert(const std::string &str, std::string & tmp){
692 return str;
693}
694
695
696template <class T>
697inline
698const T & StringTools::lazyConvert(const std::string &str, T & dst){
699 std::stringstream sstr(str);
700 sstr >> dst;
701 return dst;
702}
703
704template <class T>
705inline
706void StringTools::convert(const std::string &str, T & dst){
707 dst = lazyConvert(str, dst);
708}
709
710
711template <class T>
712inline
713T StringTools::convert(const std::string &s){
714 T tmp;
715 tmp = lazyConvert(s, tmp);
716 return tmp;
717}
718
719
720
721
722template <>
723inline
724std::string & StringTools::import(const std::string & src, std::string & dst){
725 dst = src;
726 return dst;
727}
728
729template <class T>
730std::string & StringTools::import(const T & x, std::string & dst){
731 std::stringstream sstr;
732 sstr << x;
733 dst.assign(sstr.str());
734 //std::cerr << __FUNCTION__ << ": " << str << '>' << target << '\n';
735 return dst;
736}
737
738
739} // drain::
740
741#endif /* STRING_H_ */
742
Definition StringTools.h:53
Definition StringTools.h:133
static void convert(const std::string &s, T &dst)
Conversion from std::string to basic types, including std::string.
Definition StringTools.h:706
static bool split2(const std::string &s, T1 &first, T2 &second, const C &separators, const std::string &trimChars=" \t\n")
Splits and trims a given std::string to a std Sequence.
static void replace(const std::string &src, const T1 &search, const T2 &repl, std::string &dst)
In src, replaces instances of 'from' to 'to', storing the result in dst.
Definition StringTools.h:220
static std::string & lowerCase(std::string &s, size_t n=std::numeric_limits< size_t >::max())
Turns n first characters lowercase. ASCII only.
Definition StringTools.cpp:412
static void replace(const std::string &src, const std::map< K, V > &m, std::string &dst)
Definition StringTools.h:284
static const T & lazyConvert(const std::string &s, T &tmp)
Convert only if needed. If T is std::string, returns s directly.
Definition StringTools.h:698
static std::ostream & join(const T &container, std::ostream &ostr, char separator=0)
Writes a STL Container (list, vector, set) to a stream, using an optional separator char (e....
Definition StringTools.h:454
static void read(std::istream &istr, std::string &s)
Read input stream and append it to s.
Definition StringTools.h:480
static std::string & convertEscaped(std::string &s)
Interpret commond special chars: tab '\t', newline ' ' and carriage return '\r'.
Definition StringTools.cpp:123
static std::string trim(const std::string &s, const std::string &trimChars=" \t\n\r")
Returns a string without leading and trailing whitespace (or str undesired chars).
Definition StringTools.cpp:252
static void replace(const std::string &src, const std::map< char, T > &m, std::ostream &ostr)
Convenience using copying of string.
Definition StringTools.h:249
static std::string & upperCase(std::string &s, size_t n=std::numeric_limits< size_t >::max())
Turns n first characters uppercase. ASCII only.
Definition StringTools.cpp:391
static bool trimScan(const std::string &s, size_t &pos1, size_t &pos2, const std::string &trimChars=" \t\n")
Returns indices to trimmed segment of s such that it can be extracted as s.substr(pos1,...
Definition StringTools.cpp:294
static void replace(const std::string &src, const S &search, const R &repl, std::ostream &ostr)
In src, replaces instances of 'search' to 'repl', storing the result in dst.
Definition StringTools.h:192
static size_t extractPrefixLength(const std::string &src1, const std::string &src2, size_t step=1)
Determine the length of a common leading part, rounding up the result with step.
Definition StringTools.cpp:355
static void split(const std::string &s, T &sequence, const C &separators, const std::string &trimChars=" \t\n")
Splits and trims a given std::string to a std Sequence.
Definition StringTools.h:564
static size_t extractPrefix(std::string &s1, std::string &s2, std::string &prefix, size_t step=1)
Extract common leading part, truncating the input strings.
Definition StringTools.h:443
static std::string trimSymmetric(const std::string &s, const std::string &leading="'\"", const std::string &trailing="")
Coupled trimming: remove a single leading and trailing char, if both found.
Definition StringTools.cpp:266
static size_t extractPrefix(const std::string &src1, const std::string &src2, std::string &prefix, std::string &dst1, std::string &dst2, size_t step=1)
Extract common leading part, truncating the source strings.
Definition StringTools.cpp:371
static void replace(const std::string &src, char search, char repl, std::ostream &ostr)
Replaces instances of 'search' to 'repl' in src.
Definition StringTools.cpp:94
static std::string join(T &container, char separator=0)
Writes a STL Container (list, vector, set) to a string, using an optional separator char (like ',...
Definition StringTools.h:471
Definition StringTools.h:72
StringWrapper(const T &x)
All the other constructors, including default constructor.
Definition StringTools.h:86
void set(const T2 &x)
Set the value from an other, user-defined dictionary.
Definition StringTools.h:116
Definition DataSelector.cpp:1277