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// NEW
47#include <list>
48#include "UniTuple.h"
49
50
51
52namespace drain {
53
54
56
57public:
58
59 static
60 bool startsWith(const std::string &s, const std::string & substring);
61
62
63 static
64 bool endsWith(const std::string &s, const std::string & substring);
65
66
68
70 static
71 std::string & upperCase(std::string & s, size_t n = std::numeric_limits<size_t>::max());
72
74
76 static
77 char upperCase(char c);
78
80
83 static
84 std::string & lowerCase(std::string & s, size_t n = std::numeric_limits<size_t>::max());
85
87
89 static
90 char lowerCase(char c);
91
92
93
95
98 static
99 void replace(const std::string &src, char search, char repl, std::ostream & ostr);
100
102
105 static
106 void replace(const std::string &src, char from, char repl, std::string &dst);
107
109
112 template <typename S, typename R>
113 static
114 void replace(const std::string &src, const S & search, const R & repl, std::ostream & ostr){
115
116 const size_t length = getLength(search);
117 std::string::size_type i = 0;
118 std::string::size_type pos;
119
120 while (true) {
121 pos = src.find(search, i);
122 if (pos == std::string::npos){
123 ostr << src.substr(i);
124 return;
125 }
126
127 // String was found
128 ostr << src.substr(i, pos-i) << repl;
129
130 // Jump over <search>: move forward len(search) chars
131 i = pos + length;
132 }
133 }
134
135
137
140 template <typename T1, typename T2>
141 static inline
142 void replace(const std::string &src, const T1 &search, const T2 & repl, std::string & dst){
143 std::stringstream result;
144 replace(src, search, repl, result);
145 dst = result.str();
146 }
147
148
150
156 /*
157 template <typename T1, typename T2>
158 static inline
159 std::string replace(const std::string &src, const T1 & search, const T2 & repl){
160 std::string dst;
161 replace(src, search, repl, dst);
162 return dst;
163 }
164 */
165
166 // MAP VERSIONS
167
169 template <typename T>
170 static
171 void replace(const std::string & src, const std::map<char,T> & m, std::ostream & ostr){
172 typename std::map<char,T>::const_iterator it;
173 for (char c: src){
174 it = m.find(c);
175 if (it == m.end()){
176 ostr << c;
177 }
178 else {
179 ostr << it->second;
180 }
181 }
182 }
183
184 template <typename T>
185 static inline
186 void replace(const std::string & src, const std::map<char,T> & m, std::string & dst){
187 std::stringstream result;
188 replace(src, m, result);
189 dst = result.str();
190 }
191
193
196 static
197 void replace(const std::string & src, const std::map<char,char> & m, std::string & dst);
198
204 template <class K, class V>
205 static inline
206 void replace(const std::string & src, const std::map<K,V> & m, std::string & dst){
207 replaceWithMap(src, m, dst);
208 }
209
210 template <class K, class V>
211 static inline
212 void replace(const std::string & src, const std::initializer_list<std::pair<K,V> > & m, std::string & dst){
213 replaceWithMap(src, m, dst);
214 }
215
217 static
218 std::string & convertEscaped(std::string &s);
219
221
231 static
232 void getSafeKey(const std::string & src, std::string & dst, const std::string & accept="_", const std::string & toUnderScore="");
233
234private:
235
236 static inline
237 size_t getLength(char c){
238 return 1;
239 };
240
241 static inline
242 size_t getLength(const std::string & s){
243 return s.length();
244 };
245
246 template <class M>
247 static inline
248 void replaceWithMap(const std::string & src, const M & m, std::string & dst){
249
250 if (m.empty()){
251 // Replace nothing in src, hence assign it directly to result.
252 if (&dst != &src){
253 dst = src; // clumsy?
254 }
255 return;
256 }
257
258 for (const auto & entry: m){
259 // std::cerr << "replacing " << entry.first << " -> " << entry.second << " in " << dst << std::endl;
260 replace(dst, entry.first, entry.second, dst);
261 }
262 }
263
264
265public:
266
267
268
270 static
271 std::string trim(const std::string &s, const std::string &trimChars=" \t\n\r");
272
274
281 static
282 std::string trimSymmetric(const std::string &s, const std::string &leading= "'\"", const std::string & trailing="");
283
284
286
297 static
298 bool trimScan(const std::string &s, std::size_t & pos1, std::size_t & pos2, const std::string &trimChars=" \t\n");
299
301
318 template <class T, class C>
319 static
320 void split(const std::string & s, T & sequence, const C &separators, const std::string & trimChars=" \t\n");
321 // int
322
324 /*
325 template <class T>
326 static inline
327 void split(const std::string & s, T & sequence, char separator=',', const std::string & trimChars=" \t\n"){
328 StringTools::split(s, sequence, std::string(1,separator), trimChars);
329 }
330 */
331
333
348 template <class T1, class T2, class C>
349 static
350 bool split2(const std::string & s, T1 & first, T2 & second, const C &separators, const std::string & trimChars=" \t\n");
351
353
359 static
360 size_t extractPrefixLength(const std::string & src1, const std::string & src2, size_t step = 1);
361
363
371 static
372 size_t extractPrefix(const std::string & src1, const std::string & src2,
373 std::string & prefix, std::string & dst1, std::string & dst2, size_t step = 1);
374
376
382 static inline
383 size_t extractPrefix(std::string & s1, std::string & s2, std::string & prefix, size_t step = 1){
384 return extractPrefix(s1, s2, prefix, s1, s2, step);
385 }
386
387
389
392 template <class T>
393 static
394 std::ostream & join(const T & container, std::ostream & ostr, char separator = 0){
395 char sep = 0;
396 for (typename T::const_iterator it = container.begin(); it != container.end(); ++it){
397 if (sep)
398 ostr << sep;
399 ostr << *it;
400 sep = separator;
401 }
402 return ostr;
403 }
404
406
409 template <class T>
410 static inline
411 std::string join(T & container, char separator = 0){
412 std::stringstream sstr;
413 StringTools::join(container, sstr, separator);
414 return sstr.str();
415 }
416
418 template <unsigned int S>
419 static
420 void read(std::istream &istr, std::string & s){
421 char buffer[S];
422 while (istr.read(buffer, S)){
423 s.append(buffer, S);
424 }
425 s.append(buffer, istr.gcount());
426 }
427
428
430
438 template <class T>
439 static
440 void convert(const std::string &s, T & dst);
441
443
449 template <class T>
450 static
451 T convert(const std::string &s);
452
453
454 template <class T>
455 static
456 std::string & import(const T & src, std::string & target);
457
458
459
460
461//private: CONSIDER!
462
464
474 template <class T>
475 static
476 const T & lazyConvert(const std::string &s, T & tmp);
477
478private:
479
480 template <class T>
481 static
482 void appendString(T & sequence, const std::string & str){
483 typename T::value_type tmp;
484 sequence.insert(sequence.end(), StringTools::lazyConvert(str, tmp));
485 }
486
487 template <class T, size_t N>
488 static
489 void appendString(drain::UniTuple<T,N> & tuple, const std::string & str){
490 std::list<T> l;
491 appendString(l, str);
492 tuple.assignSequence(l);
493 // if (tuple.fill && (l.size() < N)){ ... }
494 //typename T::value_type tmp;
495 //sequence.insert(sequence.end(), StringTools::lazyConvert(str, tmp));
496 }
497
498
499 template <class T>
500 static
501 void appendSubstring(T & sequence, const std::string & str, std::string::size_type pos, std::string::size_type n){
502
503 if (n > 0){
504 appendString(sequence, str.substr(pos, n));
505 }
506 else {
507 appendString(sequence, "");
508 }
509
510 }
511
512};
513
514// TODO: consider (optional) skipping empties
515template <class T, class C>
516void StringTools::split(const std::string & str, T & sequence, const C & separators, const std::string & trimChars){
517
518 sequence.clear();
519
520 const bool TRIM = !trimChars.empty();
521 const std::string::size_type n = str.size();
522
523 std::string::size_type pos1 = 0; // Start of segment
524 std::string::size_type pos2 = n; // std::string::npos; // End of segment (index of last char + 1)
525
526 // TODO: consider (optional) skipping empties
527 //int segmentCount=0;
528
529 if (false){ //separators.empty()){ // = no split! :-)
530
531 if (TRIM){
532 StringTools::trimScan(str, pos1, pos2, trimChars);
533 appendSubstring(sequence, str, pos1, pos2-pos1);
534 }
535 else
536 appendString(sequence, str);
537
538 return; // 0;
539 }
540 else {
541
542 // Index of the next separator position
543 std::string::size_type pos = pos1; // "irreversible"
544
545 while (true) {
546
547 pos1 = pos;
548 pos = str.find_first_of(separators, pos);
549 if (pos == std::string::npos){
550 pos2 = n;
551 if (TRIM){
552 StringTools::trimScan(str, pos1, pos2, trimChars);
553 }
554 appendSubstring(sequence, str, pos1, pos2-pos1);
555 return; // segmentCount;
556 }
557 else {
558 pos2 = pos;
559 if (TRIM){
560 StringTools::trimScan(str, pos1, pos2, trimChars);
561 }
562 appendSubstring(sequence, str, pos1, pos2-pos1);
563 pos = str.find_first_not_of(trimChars, pos+1); // if separator is space, or other also in trimChars
564 //pos = str.find_last_not_of(trimChars, pos);
565 //++pos; // for the next round
566 }
567
568 }
569 }
570}
571
572/*
573template <>
574bool StringTools::split2(const std::string & s, std::string & first, std::string & second, const char *separators, const std::string & trimChars);
575*/
576
577template <class T1, class T2, class S>
578bool StringTools::split2(const std::string & s, T1 & first, T2 & second, const S & separators, const std::string & trimChars){
579
580 std::size_t i = s.find_first_of(separators);
581
582 if (i != std::string::npos){ // input of type "key=value" found
583
584 std::string srcFirst(s, 0, i);
585 ++i;
586 std::string srcSecond(s, std::min(s.size(), i));
587
588 if (!trimChars.empty()){
589 first = lazyConvert(StringTools::trim(srcFirst, trimChars), first); // first=first should not clear the object!
590 }
591 else {
592 first = lazyConvert(srcFirst, first); // Note: first=first should not clear the object!
593 }
594
595 if (!srcSecond.empty()){
596 if (!trimChars.empty()){
597 second = lazyConvert(StringTools::trim(srcSecond), second);
598 }
599 else {
600 second = lazyConvert(srcSecond, second);
601 }
602 }
603
604 /*
605 ++i;
606 if (i<s.size()){
607 //std::cerr << "toka " << s.substr(i) << '\n';
608 if (!trimChars.empty()){
609 // sstr2 << StringTools::trim(s.substr(i), trimChars);
610 // sstr2 >> second;
611 second = lazyConvert(StringTools::trim(s.substr(i), trimChars), second);
612 }
613 else {
614 // sstr2 << s.substr(i);
615 // sstr2 >> second;
616 second = lazyConvert(s.substr(i), second);
617 }
618 }
619 */
620 return true;
621 }
622 else {
623 // std::stringstream sstr;
624 if (trimChars.empty()){
625 //sstr << s;
626 //sstr >> first;
627 first = lazyConvert(s, first);
628 }
629 else {
630 // sstr << StringTools::trim(s, trimChars);
631 // sstr >> first;
632 first = lazyConvert(StringTools::trim(s, trimChars), first);
633 }
634 return false;
635 }
636
637
638}
639
640
641
642
643
644
645
646template <>
647inline
648const std::string & StringTools::lazyConvert(const std::string &str, std::string & tmp){
649 return str;
650}
651
652
653template <class T>
654inline
655const T & StringTools::lazyConvert(const std::string &str, T & dst){
656 std::stringstream sstr(str);
657 sstr >> dst;
658 return dst;
659}
660
661template <class T>
662inline
663void StringTools::convert(const std::string &str, T & dst){
664 dst = lazyConvert(str, dst);
665}
666
667
668template <class T>
669inline
670T StringTools::convert(const std::string &s){
671 T tmp;
672 tmp = lazyConvert(s, tmp);
673 return tmp;
674}
675
676
677
678
679template <>
680inline
681std::string & StringTools::import(const std::string & src, std::string & dst){
682 dst = src;
683 return dst;
684}
685
686template <class T>
687std::string & StringTools::import(const T & x, std::string & dst){
688 std::stringstream sstr;
689 sstr << x;
690 dst.assign(sstr.str());
691 //std::cerr << __FUNCTION__ << ": " << str << '>' << target << '\n';
692 return dst;
693}
694
695
696} // drain::
697
698#endif /* STRING_H_ */
699
Definition StringTools.h:55
static void convert(const std::string &s, T &dst)
Conversion from std::string to basic types, including std::string.
Definition StringTools.h:663
static void getSafeKey(const std::string &src, std::string &dst, const std::string &accept="_", const std::string &toUnderScore="")
Ensure a safe variable name.
Definition StringTools.cpp:136
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:321
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:142
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:439
static void replace(const std::string &src, const std::map< K, V > &m, std::string &dst)
Definition StringTools.h:206
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:655
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:394
static void read(std::istream &istr, std::string &s)
Read input stream and append it to s.
Definition StringTools.h:420
static std::string & convertEscaped(std::string &s)
Interpret common special chars: tab '\t', newline '\n' and carriage return '\r'.
Definition StringTools.cpp:122
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:279
static void replace(const std::string &src, const std::map< char, T > &m, std::ostream &ostr)
Convenience using copying of string.
Definition StringTools.h:171
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:418
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:114
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:382
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:516
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:383
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:293
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:398
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:93
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:411
tuplebase_t & assignSequence(T &sequence, bool LENIENT=false)
Proposed for tuples only; derived classes should not shadow this.
Definition TupleBase.h:287
Tuple of N elements of type T.
Definition UniTuple.h:65
Definition Data.h:1473