Loading...
Searching...
No Matches
String.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//#include "RegExp.h"
50
51namespace drain {
52
54
55public:
56
57 static
58 bool startsWith(const std::string &s, const std::string & substring);
59
60
61 static
62 bool endsWith(const std::string &s, const std::string & substring);
63
64
66
68 static
69 std::string & upperCase(std::string & s, size_t n = std::numeric_limits<size_t>::max());
70
72
74 static
75 char upperCase(char c);
76
78
81 static
82 std::string & lowerCase(std::string & s, size_t n = std::numeric_limits<size_t>::max());
83
85
87 static
88 char lowerCase(char c);
89
90
91
93
96 static
97 void replace(const std::string &src, char search, char repl, std::ostream & ostr);
98
100
103 static
104 void replace(const std::string &src, char from, char repl, std::string &dst);
105
107
110 template <typename S, typename R>
111 static
112 void replace(const std::string &src, const S & search, const R & repl, std::ostream & ostr){
113
114 const size_t length = getLength(search);
115 std::string::size_type i = 0;
116 std::string::size_type pos;
117
118 while (true) {
119 pos = src.find(search, i);
120 if (pos == std::string::npos){
121 ostr << src.substr(i);
122 return;
123 }
124
125 // String was found
126 ostr << src.substr(i, pos-i) << repl;
127
128 // Jump over <search>: move forward len(search) chars
129 i = pos + length;
130 }
131 }
132
133
135
138 template <typename T1, typename T2>
139 static inline
140 void replace(const std::string &src, const T1 &search, const T2 & repl, std::string & dst){
141 std::stringstream result;
142 replace(src, search, repl, result);
143 dst = result.str();
144 }
145
146
148
154 /*
155 template <typename T1, typename T2>
156 static inline
157 std::string replace(const std::string &src, const T1 & search, const T2 & repl){
158 std::string dst;
159 replace(src, search, repl, dst);
160 return dst;
161 }
162 */
163
164 // MAP VERSIONS
165
167 template <typename T>
168 static
169 void replace(const std::string & src, const std::map<char,T> & m, std::ostream & ostr){
170 typename std::map<char,T>::const_iterator it;
171 for (char c: src){
172 it = m.find(c);
173 if (it == m.end()){
174 ostr << c;
175 }
176 else {
177 ostr << it->second;
178 }
179 }
180 };
181
182 template <typename T>
183 static inline
184 void replace(const std::string & src, const std::map<char,T> & m, std::string & dst){
185 std::stringstream result;
186 replace(src, m, result);
187 dst = result.str();
188 }
189
191
194 static
195 void replace(const std::string & src, const std::map<char,char> & m, std::string & dst);
196
202 template <class K, class V>
203 static inline
204 void replace(const std::string & src, const std::map<K,V> & m, std::string & dst){
205 replaceWithMap(src, m, dst);
206 };
207
208 template <class K, class V>
209 static inline
210 void replace(const std::string & src, const std::initializer_list<std::pair<K,V> > & m, std::string & dst){
211 replaceWithMap(src, m, dst);
212 };
213
214
215private:
216
217 static inline
218 size_t getLength(char c){
219 return 1;
220 };
221
222 static inline
223 size_t getLength(const std::string & s){
224 return s.length();
225 };
226
227 template <class M>
228 static inline
229 void replaceWithMap(const std::string & src, const M & m, std::string & dst){
230
231 if (m.empty()){
232 // Replace nothing in src, hence assign it directly to result.
233 if (&dst != &src){
234 dst = src; // clumsy?
235 }
236 return;
237 }
238
239 for (const auto & entry: m){
240 // std::cerr << "replacing " << entry.first << " -> " << entry.second << " in " << dst << std::endl;
241 replace(dst, entry.first, entry.second, dst);
242 }
243 };
244
245
246public:
247
248
249
251 static
252 std::string trim(const std::string &s, const std::string &trimChars=" \t\n\r");
253
255
262 static
263 std::string trimSymmetric(const std::string &s, const std::string &leading= "'\"", const std::string & trailing="");
264
265
267
278 static
279 bool trimScan(const std::string &s, size_t & pos1, size_t & pos2, const std::string &trimChars=" \t\n");
280
282
295 template <class T, class C>
296 static
297 void split(const std::string & s, T & sequence, const C &separators, const std::string & trimChars=" \t\n");
298
300 /*
301 template <class T>
302 static inline
303 void split(const std::string & s, T & sequence, char separator=',', const std::string & trimChars=" \t\n"){
304 StringTools::split(s, sequence, std::string(1,separator), trimChars);
305 }
306 */
307
309
324 template <class T1, class T2, class C>
325 static
326 bool split2(const std::string & s, T1 & first, T2 & second, const C &separators, const std::string & trimChars=" \t\n");
327
329
335 static
336 size_t extractPrefixLength(const std::string & src1, const std::string & src2, size_t step = 1);
337
339
347 static
348 size_t extractPrefix(const std::string & src1, const std::string & src2,
349 std::string & prefix, std::string & dst1, std::string & dst2, size_t step = 1);
350
352
358 static inline
359 size_t extractPrefix(std::string & s1, std::string & s2, std::string & prefix, size_t step = 1){
360 return extractPrefix(s1, s2, prefix, s1, s2, step);
361 }
362
363
365
368 template <class T>
369 static
370 std::ostream & join(const T & container, std::ostream & ostr, char separator = 0){
371 char sep = 0;
372 for (typename T::const_iterator it = container.begin(); it != container.end(); ++it){
373 if (sep)
374 ostr << sep;
375 ostr << *it;
376 sep = separator;
377 }
378 return ostr;
379 }
380
382
385 template <class T>
386 static inline
387 std::string join(T & container, char separator = 0){
388 std::stringstream sstr;
389 StringTools::join(container, sstr, separator);
390 return sstr.str();
391 }
392
394 template <unsigned int S>
395 static
396 void read(std::istream &istr, std::string & s){
397 char buffer[S];
398 while (istr.read(buffer, S)){
399 s.append(buffer, S);
400 }
401 s.append(buffer, istr.gcount());
402 }
403
404
406
414 template <class T>
415 static
416 void convert(const std::string &s, T & dst);
417
419
425 template <class T>
426 static
427 T convert(const std::string &s);
428
429 template <class T>
430 static
431 std::string & import(const T & src, std::string & target);
432
433
434
435
436//private: CONSIDER!
437
439
449 template <class T>
450 static
451 const T & lazyConvert(const std::string &s, T & tmp);
452
453private:
454
455 template <class T>
456 static
457 void appendString(T & sequence, const std::string & str){
458 typename T::value_type tmp;
459 sequence.insert(sequence.end(), StringTools::lazyConvert(str, tmp));
460 }
461
462 template <class T>
463 static
464 void appendSubstring(T & sequence, const std::string & str, std::string::size_type pos, std::string::size_type n){
465
466 if (n > 0){
467 appendString(sequence, str.substr(pos, n));
468 }
469 else {
470 appendString(sequence, "");
471 }
472
473 }
474
475};
476
477
478template <class T, class C>
479void StringTools::split(const std::string & str, T & sequence, const C & separators, const std::string & trimChars){
480
481 sequence.clear();
482
483 const bool TRIM = !trimChars.empty();
484 const std::string::size_type n = str.size();
485
486 std::string::size_type pos1 = 0; // Start of segment
487 std::string::size_type pos2 = n; // std::string::npos; // End of segment (index of last char + 1)
488
489 if (false){ //separators.empty()){ // = no split! :-)
490
491 if (TRIM){
492 StringTools::trimScan(str, pos1, pos2, trimChars);
493 appendSubstring(sequence, str, pos1, pos2-pos1);
494 }
495 else
496 appendString(sequence, str);
497
498 return;
499 }
500 else {
501
502 // Index of the next separator position
503 std::string::size_type pos = pos1; // "irreversible"
504
505 while (true) {
506
507 pos1 = pos;
508 pos = str.find_first_of(separators, pos);
509 if (pos == std::string::npos){
510 pos2 = n;
511 if (TRIM)
512 StringTools::trimScan(str, pos1, pos2, trimChars);
513 appendSubstring(sequence, str, pos1, pos2-pos1);
514 return;
515 }
516 else {
517 pos2 = pos;
518 if (TRIM)
519 StringTools::trimScan(str, pos1, pos2, trimChars);
520 appendSubstring(sequence, str, pos1, pos2-pos1);
521 pos = str.find_first_not_of(trimChars, pos+1); // if separator is space, or other also in trimChars
522 //pos = str.find_last_not_of(trimChars, pos);
523 //++pos; // for the next round
524 }
525
526 }
527 }
528}
529
530/*
531template <>
532bool StringTools::split2(const std::string & s, std::string & first, std::string & second, const char *separators, const std::string & trimChars);
533*/
534
535template <class T1, class T2, class S>
536bool StringTools::split2(const std::string & s, T1 & first, T2 & second, const S & separators, const std::string & trimChars){
537
538 std::size_t i = s.find_first_of(separators);
539
540 if (i != std::string::npos){ // input of type "key=value" found
541
542 std::string srcFirst(s, 0, i);
543 ++i;
544 std::string srcSecond(s, std::min(s.size(), i));
545
546 if (!trimChars.empty()){
547 first = lazyConvert(StringTools::trim(srcFirst, trimChars), first); // first=first should not clear the object!
548 }
549 else {
550 first = lazyConvert(srcFirst, first); // Note: first=first should not clear the object!
551 }
552
553 if (!srcSecond.empty()){
554 if (!trimChars.empty()){
555 second = lazyConvert(StringTools::trim(srcSecond), second);
556 }
557 else {
558 second = lazyConvert(srcSecond, second);
559 }
560 }
561
562 /*
563 ++i;
564 if (i<s.size()){
565 //std::cerr << "toka " << s.substr(i) << '\n';
566 if (!trimChars.empty()){
567 // sstr2 << StringTools::trim(s.substr(i), trimChars);
568 // sstr2 >> second;
569 second = lazyConvert(StringTools::trim(s.substr(i), trimChars), second);
570 }
571 else {
572 // sstr2 << s.substr(i);
573 // sstr2 >> second;
574 second = lazyConvert(s.substr(i), second);
575 }
576 }
577 */
578 return true;
579 }
580 else {
581 // std::stringstream sstr;
582 if (trimChars.empty()){
583 //sstr << s;
584 //sstr >> first;
585 first = lazyConvert(s, first);
586 }
587 else {
588 // sstr << StringTools::trim(s, trimChars);
589 // sstr >> first;
590 first = lazyConvert(StringTools::trim(s, trimChars), first);
591 }
592 return false;
593 }
594
595
596}
597
598
599
600
601
602
603
604template <>
605inline
606const std::string & StringTools::lazyConvert(const std::string &str, std::string & tmp){
607 return str;
608}
609
610
611template <class T>
612inline
613const T & StringTools::lazyConvert(const std::string &str, T & dst){
614 std::stringstream sstr(str);
615 sstr >> dst;
616 return dst;
617}
618
619template <class T>
620inline
621void StringTools::convert(const std::string &str, T & dst){
622 dst = lazyConvert(str, dst);
623}
624
625
626template <class T>
627inline
628T StringTools::convert(const std::string &s){
629 T tmp;
630 tmp = lazyConvert(s, tmp);
631 return tmp;
632}
633
634
635
636
637template <>
638inline
639std::string & StringTools::import(const std::string & src, std::string & dst){
640 dst = src;
641 return dst;
642}
643
644template <class T>
645std::string & StringTools::import(const T & x, std::string & dst){
646 std::stringstream sstr;
647 sstr << x;
648 dst.assign(sstr.str());
649 //std::cerr << __FUNCTION__ << ": " << str << '>' << target << '\n';
650 return dst;
651}
652
653
654} // drain::
655
656#endif /* STRING_H_ */
657
Definition String.h:53
static void convert(const std::string &s, T &dst)
Conversion from std::string to basic types, including std::string.
Definition String.h:621
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 String.h:140
static std::string & lowerCase(std::string &s, size_t n=std::numeric_limits< size_t >::max())
Turns n first characters lowercase. ASCII only.
Definition String.cpp:399
static void replace(const std::string &src, const std::map< K, V > &m, std::string &dst)
Definition String.h:204
static const T & lazyConvert(const std::string &s, T &tmp)
Convert only if needed. If T is std::string, returns s directly.
Definition String.h:613
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 String.h:370
static void read(std::istream &istr, std::string &s)
Read input stream and append it to s.
Definition String.h:396
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 String.cpp:239
static void replace(const std::string &src, const std::map< char, T > &m, std::ostream &ostr)
Convenience using copying of string.
Definition String.h:169
static std::string & upperCase(std::string &s, size_t n=std::numeric_limits< size_t >::max())
Turns n first characters uppercase. ASCII only.
Definition String.cpp:378
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 String.cpp:281
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 String.h:112
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 String.cpp:342
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 String.h:479
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 String.h:359
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 String.cpp:253
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 String.cpp:358
static void replace(const std::string &src, char search, char repl, std::ostream &ostr)
Replaces instances of 'search' to 'repl' in src.
Definition String.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 String.h:387
Definition DataSelector.cpp:1277