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_TOOLS
39#define DRAIN_STRING_TOOLS
40
41#include <limits>
42#include <map>
43#include <string>
44#include <sstream>
45
46
47
48namespace drain {
49
50
52
53public:
54
55 static
56 bool startsWith(const std::string &s, const std::string & substring);
57
58
59 static
60 bool endsWith(const std::string &s, const std::string & substring);
61
62
64
66 static
67 std::string & upperCase(std::string & s, size_t n = std::numeric_limits<size_t>::max());
68
70
72 static
73 char upperCase(char c);
74
76
79 static
80 std::string & lowerCase(std::string & s, size_t n = std::numeric_limits<size_t>::max());
81
83
85 static
86 char lowerCase(char c);
87
88
89
91
94 static
95 void replace(const std::string &src, char search, char repl, std::ostream & ostr);
96
98
101 static
102 void replace(const std::string &src, char from, char repl, std::string &dst);
103
105
108 template <typename S, typename R>
109 static
110 void replace(const std::string &src, const S & search, const R & repl, std::ostream & ostr){
111
112 const size_t length = getLength(search);
113 std::string::size_type i = 0;
114 std::string::size_type pos;
115
116 while (true) {
117 pos = src.find(search, i);
118 if (pos == std::string::npos){
119 ostr << src.substr(i);
120 return;
121 }
122
123 // String was found
124 ostr << src.substr(i, pos-i) << repl;
125
126 // Jump over <search>: move forward len(search) chars
127 i = pos + length;
128 }
129 }
130
131
133
136 template <typename T1, typename T2>
137 static inline
138 void replace(const std::string &src, const T1 &search, const T2 & repl, std::string & dst){
139 std::stringstream result;
140 replace(src, search, repl, result);
141 dst = result.str();
142 }
143
144
146
152 /*
153 template <typename T1, typename T2>
154 static inline
155 std::string replace(const std::string &src, const T1 & search, const T2 & repl){
156 std::string dst;
157 replace(src, search, repl, dst);
158 return dst;
159 }
160 */
161
162 // MAP VERSIONS
163
165 template <typename T>
166 static
167 void replace(const std::string & src, const std::map<char,T> & m, std::ostream & ostr){
168 typename std::map<char,T>::const_iterator it;
169 for (char c: src){
170 it = m.find(c);
171 if (it == m.end()){
172 ostr << c;
173 }
174 else {
175 ostr << it->second;
176 }
177 }
178 };
179
180 template <typename T>
181 static inline
182 void replace(const std::string & src, const std::map<char,T> & m, std::string & dst){
183 std::stringstream result;
184 replace(src, m, result);
185 dst = result.str();
186 }
187
189
192 static
193 void replace(const std::string & src, const std::map<char,char> & m, std::string & dst);
194
200 template <class K, class V>
201 static inline
202 void replace(const std::string & src, const std::map<K,V> & m, std::string & dst){
203 replaceWithMap(src, m, dst);
204 };
205
206 template <class K, class V>
207 static inline
208 void replace(const std::string & src, const std::initializer_list<std::pair<K,V> > & m, std::string & dst){
209 replaceWithMap(src, m, dst);
210 };
211
213 static
214 std::string & convertEscaped(std::string &s);
215
216
217private:
218
219 static inline
220 size_t getLength(char c){
221 return 1;
222 };
223
224 static inline
225 size_t getLength(const std::string & s){
226 return s.length();
227 };
228
229 template <class M>
230 static inline
231 void replaceWithMap(const std::string & src, const M & m, std::string & dst){
232
233 if (m.empty()){
234 // Replace nothing in src, hence assign it directly to result.
235 if (&dst != &src){
236 dst = src; // clumsy?
237 }
238 return;
239 }
240
241 for (const auto & entry: m){
242 // std::cerr << "replacing " << entry.first << " -> " << entry.second << " in " << dst << std::endl;
243 replace(dst, entry.first, entry.second, dst);
244 }
245 };
246
247
248public:
249
250
251
253 static
254 std::string trim(const std::string &s, const std::string &trimChars=" \t\n\r");
255
257
264 static
265 std::string trimSymmetric(const std::string &s, const std::string &leading= "'\"", const std::string & trailing="");
266
267
269
280 static
281 bool trimScan(const std::string &s, std::size_t & pos1, std::size_t & pos2, const std::string &trimChars=" \t\n");
282
284
301 template <class T, class C>
302 static
303 void split(const std::string & s, T & sequence, const C &separators, const std::string & trimChars=" \t\n");
304 // int
305
307 /*
308 template <class T>
309 static inline
310 void split(const std::string & s, T & sequence, char separator=',', const std::string & trimChars=" \t\n"){
311 StringTools::split(s, sequence, std::string(1,separator), trimChars);
312 }
313 */
314
316
331 template <class T1, class T2, class C>
332 static
333 bool split2(const std::string & s, T1 & first, T2 & second, const C &separators, const std::string & trimChars=" \t\n");
334
336
342 static
343 size_t extractPrefixLength(const std::string & src1, const std::string & src2, size_t step = 1);
344
346
354 static
355 size_t extractPrefix(const std::string & src1, const std::string & src2,
356 std::string & prefix, std::string & dst1, std::string & dst2, size_t step = 1);
357
359
365 static inline
366 size_t extractPrefix(std::string & s1, std::string & s2, std::string & prefix, size_t step = 1){
367 return extractPrefix(s1, s2, prefix, s1, s2, step);
368 }
369
370
372
375 template <class T>
376 static
377 std::ostream & join(const T & container, std::ostream & ostr, char separator = 0){
378 char sep = 0;
379 for (typename T::const_iterator it = container.begin(); it != container.end(); ++it){
380 if (sep)
381 ostr << sep;
382 ostr << *it;
383 sep = separator;
384 }
385 return ostr;
386 }
387
389
392 template <class T>
393 static inline
394 std::string join(T & container, char separator = 0){
395 std::stringstream sstr;
396 StringTools::join(container, sstr, separator);
397 return sstr.str();
398 }
399
401 template <unsigned int S>
402 static
403 void read(std::istream &istr, std::string & s){
404 char buffer[S];
405 while (istr.read(buffer, S)){
406 s.append(buffer, S);
407 }
408 s.append(buffer, istr.gcount());
409 }
410
411
413
421 template <class T>
422 static
423 void convert(const std::string &s, T & dst);
424
426
432 template <class T>
433 static
434 T convert(const std::string &s);
435
436
437 template <class T>
438 static
439 std::string & import(const T & src, std::string & target);
440
441
442
443
444//private: CONSIDER!
445
447
457 template <class T>
458 static
459 const T & lazyConvert(const std::string &s, T & tmp);
460
461private:
462
463 template <class T>
464 static
465 void appendString(T & sequence, const std::string & str){
466 typename T::value_type tmp;
467 sequence.insert(sequence.end(), StringTools::lazyConvert(str, tmp));
468 }
469
470 template <class T>
471 static
472 void appendSubstring(T & sequence, const std::string & str, std::string::size_type pos, std::string::size_type n){
473
474 if (n > 0){
475 appendString(sequence, str.substr(pos, n));
476 }
477 else {
478 appendString(sequence, "");
479 }
480
481 }
482
483};
484
485// TODO: consider (optional) skipping empties
486template <class T, class C>
487void StringTools::split(const std::string & str, T & sequence, const C & separators, const std::string & trimChars){
488
489 sequence.clear();
490
491 const bool TRIM = !trimChars.empty();
492 const std::string::size_type n = str.size();
493
494 std::string::size_type pos1 = 0; // Start of segment
495 std::string::size_type pos2 = n; // std::string::npos; // End of segment (index of last char + 1)
496
497 // TODO: consider (optional) skipping empties
498 //int segmentCount=0;
499
500 if (false){ //separators.empty()){ // = no split! :-)
501
502 if (TRIM){
503 StringTools::trimScan(str, pos1, pos2, trimChars);
504 appendSubstring(sequence, str, pos1, pos2-pos1);
505 }
506 else
507 appendString(sequence, str);
508
509 return; // 0;
510 }
511 else {
512
513 // Index of the next separator position
514 std::string::size_type pos = pos1; // "irreversible"
515
516 while (true) {
517
518 pos1 = pos;
519 pos = str.find_first_of(separators, pos);
520 if (pos == std::string::npos){
521 pos2 = n;
522 if (TRIM){
523 StringTools::trimScan(str, pos1, pos2, trimChars);
524 }
525 appendSubstring(sequence, str, pos1, pos2-pos1);
526 return; // segmentCount;
527 }
528 else {
529 pos2 = pos;
530 if (TRIM){
531 StringTools::trimScan(str, pos1, pos2, trimChars);
532 }
533 appendSubstring(sequence, str, pos1, pos2-pos1);
534 pos = str.find_first_not_of(trimChars, pos+1); // if separator is space, or other also in trimChars
535 //pos = str.find_last_not_of(trimChars, pos);
536 //++pos; // for the next round
537 }
538
539 }
540 }
541}
542
543/*
544template <>
545bool StringTools::split2(const std::string & s, std::string & first, std::string & second, const char *separators, const std::string & trimChars);
546*/
547
548template <class T1, class T2, class S>
549bool StringTools::split2(const std::string & s, T1 & first, T2 & second, const S & separators, const std::string & trimChars){
550
551 std::size_t i = s.find_first_of(separators);
552
553 if (i != std::string::npos){ // input of type "key=value" found
554
555 std::string srcFirst(s, 0, i);
556 ++i;
557 std::string srcSecond(s, std::min(s.size(), i));
558
559 if (!trimChars.empty()){
560 first = lazyConvert(StringTools::trim(srcFirst, trimChars), first); // first=first should not clear the object!
561 }
562 else {
563 first = lazyConvert(srcFirst, first); // Note: first=first should not clear the object!
564 }
565
566 if (!srcSecond.empty()){
567 if (!trimChars.empty()){
568 second = lazyConvert(StringTools::trim(srcSecond), second);
569 }
570 else {
571 second = lazyConvert(srcSecond, second);
572 }
573 }
574
575 /*
576 ++i;
577 if (i<s.size()){
578 //std::cerr << "toka " << s.substr(i) << '\n';
579 if (!trimChars.empty()){
580 // sstr2 << StringTools::trim(s.substr(i), trimChars);
581 // sstr2 >> second;
582 second = lazyConvert(StringTools::trim(s.substr(i), trimChars), second);
583 }
584 else {
585 // sstr2 << s.substr(i);
586 // sstr2 >> second;
587 second = lazyConvert(s.substr(i), second);
588 }
589 }
590 */
591 return true;
592 }
593 else {
594 // std::stringstream sstr;
595 if (trimChars.empty()){
596 //sstr << s;
597 //sstr >> first;
598 first = lazyConvert(s, first);
599 }
600 else {
601 // sstr << StringTools::trim(s, trimChars);
602 // sstr >> first;
603 first = lazyConvert(StringTools::trim(s, trimChars), first);
604 }
605 return false;
606 }
607
608
609}
610
611
612
613
614
615
616
617template <>
618inline
619const std::string & StringTools::lazyConvert(const std::string &str, std::string & tmp){
620 return str;
621}
622
623
624template <class T>
625inline
626const T & StringTools::lazyConvert(const std::string &str, T & dst){
627 std::stringstream sstr(str);
628 sstr >> dst;
629 return dst;
630}
631
632template <class T>
633inline
634void StringTools::convert(const std::string &str, T & dst){
635 dst = lazyConvert(str, dst);
636}
637
638
639template <class T>
640inline
641T StringTools::convert(const std::string &s){
642 T tmp;
643 tmp = lazyConvert(s, tmp);
644 return tmp;
645}
646
647
648
649
650template <>
651inline
652std::string & StringTools::import(const std::string & src, std::string & dst){
653 dst = src;
654 return dst;
655}
656
657template <class T>
658std::string & StringTools::import(const T & x, std::string & dst){
659 std::stringstream sstr;
660 sstr << x;
661 dst.assign(sstr.str());
662 //std::cerr << __FUNCTION__ << ": " << str << '>' << target << '\n';
663 return dst;
664}
665
666
667} // drain::
668
669#endif /* STRING_H_ */
670
Definition StringTools.h:51
static void convert(const std::string &s, T &dst)
Conversion from std::string to basic types, including std::string.
Definition StringTools.h:634
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 bool trimScan(const std::string &s, std::size_t &pos1, std::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 T1 &search, const T2 &repl, std::string &dst)
In src, replaces instances of 'from' to 'to', storing the result in dst.
Definition StringTools.h:138
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:202
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:626
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:377
static void read(std::istream &istr, std::string &s)
Read input stream and append it to s.
Definition StringTools.h:403
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:167
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 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:110
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:487
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:366
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:394
Definition DataSelector.cpp:1277