1 // Copyright (C) 2006  Davis E. King (davis@dlib.net)
2 // License: Boost Software License   See LICENSE.txt for the full license.
3 #ifndef DLIB_STRINg_
4 #define DLIB_STRINg_
5 
6 #include "string_abstract.h"
7 #include <sstream>
8 #include "../algs.h"
9 #include <string>
10 #include <iostream>
11 #include <iomanip>
12 #include "../error.h"
13 #include "../assert.h"
14 #include "../uintn.h"
15 #include <cctype>
16 #include <algorithm>
17 #include <vector>
18 #include "../enable_if.h"
19 
20 namespace dlib
21 {
22 
23 // ----------------------------------------------------------------------------------------
24 
25     template <
26         typename charT,
27         typename traits,
28         typename alloc
29         >
narrow(const std::basic_string<charT,traits,alloc> & str)30     inline const typename disable_if<is_same_type<charT,char>,std::string>::type narrow (
31         const std::basic_string<charT,traits,alloc>& str
32     )
33     {
34         std::string temp;
35         temp.reserve(str.size());
36         std::string::size_type i;
37         for (i = 0; i < str.size(); ++i)
38         {
39             if (zero_extend_cast<unsigned long>(str[i]) > 255)
40                 temp += ' ';
41             else
42                 temp += zero_extend_cast<char>(str[i]);
43         }
44         return temp;
45     }
46 
47     template <
48         typename charT,
49         typename traits,
50         typename alloc
51         >
narrow(const std::basic_string<charT,traits,alloc> & str)52     inline const typename enable_if<is_same_type<charT,char>,std::string>::type narrow (
53         const std::basic_string<charT,traits,alloc>& str
54     )
55     {
56         return str;
57     }
58 
59 // ----------------------------------------------------------------------------------------
60 
61     template <
62         typename traits,
63         typename alloc
64         >
tolower(const std::basic_string<char,traits,alloc> & str)65     const std::basic_string<char,traits,alloc> tolower (
66         const std::basic_string<char,traits,alloc>& str
67     )
68     {
69         std::basic_string<char,traits,alloc> temp;
70 
71         temp.resize(str.size());
72 
73         for (typename std::basic_string<char,traits,alloc>::size_type i = 0; i < str.size(); ++i)
74             temp[i] = (char)std::tolower(str[i]);
75 
76         return temp;
77     }
78 
79 // ----------------------------------------------------------------------------------------
80 
81     template <
82         typename traits,
83         typename alloc
84         >
toupper(const std::basic_string<char,traits,alloc> & str)85     const std::basic_string<char,traits,alloc> toupper (
86         const std::basic_string<char,traits,alloc>& str
87     )
88     {
89         std::basic_string<char,traits,alloc> temp;
90 
91         temp.resize(str.size());
92 
93         for (typename std::basic_string<char,traits,alloc>::size_type i = 0; i < str.size(); ++i)
94             temp[i] = (char)std::toupper(str[i]);
95 
96         return temp;
97     }
98 
99 // ----------------------------------------------------------------------------------------
100 
101     template <
102         typename traits,
103         typename alloc
104         >
strings_equal_ignore_case(const std::basic_string<char,traits,alloc> & str1,const std::basic_string<char,traits,alloc> & str2)105     bool strings_equal_ignore_case (
106         const std::basic_string<char,traits,alloc>& str1,
107         const std::basic_string<char,traits,alloc>& str2
108     )
109     {
110         if (str1.size() != str2.size())
111             return false;
112 
113         for (typename std::basic_string<char,traits,alloc>::size_type i = 0; i < str1.size(); ++i)
114         {
115             if (std::tolower(str1[i]) != std::tolower(str2[i]))
116                 return false;
117         }
118 
119         return true;
120     }
121 
122     template <
123         typename traits,
124         typename alloc
125         >
strings_equal_ignore_case(const std::basic_string<char,traits,alloc> & str1,const char * str2)126     bool strings_equal_ignore_case (
127         const std::basic_string<char,traits,alloc>& str1,
128         const char* str2
129     )
130     {
131         typename std::basic_string<char,traits,alloc>::size_type i;
132         for (i = 0; i < str1.size(); ++i)
133         {
134             // if we hit the end of str2 then the strings aren't the same length
135             if (str2[i] == '\0')
136                 return false;
137 
138             if (std::tolower(str1[i]) != std::tolower(str2[i]))
139                 return false;
140         }
141 
142         // This happens when str2 is longer than str1
143         if (str2[i] != '\0')
144             return false;
145 
146         return true;
147     }
148 
149     template <
150         typename traits,
151         typename alloc
152         >
strings_equal_ignore_case(const char * str1,const std::basic_string<char,traits,alloc> & str2)153     bool strings_equal_ignore_case (
154         const char* str1,
155         const std::basic_string<char,traits,alloc>& str2
156     )
157     {
158         return strings_equal_ignore_case(str2, str1);
159     }
160 
161 // ----------------------------------------------------------------------------------------
162 
163     template <
164         typename traits,
165         typename alloc
166         >
strings_equal_ignore_case(const std::basic_string<char,traits,alloc> & str1,const std::basic_string<char,traits,alloc> & str2,unsigned long num)167     bool strings_equal_ignore_case (
168         const std::basic_string<char,traits,alloc>& str1,
169         const std::basic_string<char,traits,alloc>& str2,
170         unsigned long num
171     )
172     {
173         if (str1.size() != str2.size() && (str1.size() < num || str2.size() < num))
174             return false;
175 
176         for (typename std::basic_string<char,traits,alloc>::size_type i = 0; i < str1.size() && i < num; ++i)
177         {
178             if (std::tolower(str1[i]) != std::tolower(str2[i]))
179                 return false;
180         }
181 
182         return true;
183     }
184 
185     template <
186         typename traits,
187         typename alloc
188         >
strings_equal_ignore_case(const std::basic_string<char,traits,alloc> & str1,const char * str2,unsigned long num)189     bool strings_equal_ignore_case (
190         const std::basic_string<char,traits,alloc>& str1,
191         const char* str2,
192         unsigned long num
193     )
194     {
195         typename std::basic_string<char,traits,alloc>::size_type i;
196         for (i = 0; i < str1.size() && i < num; ++i)
197         {
198             // if we hit the end of str2 then the strings aren't the same length
199             if (str2[i] == '\0')
200                 return false;
201 
202             if (std::tolower(str1[i]) != std::tolower(str2[i]))
203                 return false;
204         }
205 
206         return true;
207     }
208 
209     template <
210         typename traits,
211         typename alloc
212         >
strings_equal_ignore_case(const char * str1,const std::basic_string<char,traits,alloc> & str2,unsigned long num)213     bool strings_equal_ignore_case (
214         const char* str1,
215         const std::basic_string<char,traits,alloc>& str2,
216         unsigned long num
217     )
218     {
219         return strings_equal_ignore_case(str2, str1, num);
220     }
221 
222 // ----------------------------------------------------------------------------------------
223 
224     class cast_to_string_error : public error
225     {
226     public:
cast_to_string_error()227         cast_to_string_error():error(ECAST_TO_STRING) {}
228     };
229 
230     template <
231         typename T
232         >
cast_to_string(const T & item)233     const std::string cast_to_string (
234         const T& item
235     )
236     {
237         std::ostringstream sout;
238         sout << item;
239         if (!sout)
240             throw cast_to_string_error();
241         return sout.str();
242     }
243 
244     // don't declare this if we are using mingw because it apparently doesn't
245     // support iostreams with wchar_t?
246 #if !(defined(__MINGW32__) && (__GNUC__ < 4))
247     template <
248         typename T
249         >
cast_to_wstring(const T & item)250     const std::wstring cast_to_wstring (
251         const T& item
252     )
253     {
254         std::basic_ostringstream<wchar_t> sout;
255         sout << item;
256         if (!sout)
257             throw cast_to_string_error();
258         return sout.str();
259     }
260 #endif
261 
262 // ----------------------------------------------------------------------------------------
263 
264     inline std::string pad_int_with_zeros (
265         int i,
266         unsigned long width = 6
267     )
268     {
269         std::ostringstream sout;
270         sout << std::setw(width) << std::setfill('0') << i;
271         return sout.str();
272     }
273 
274 // ----------------------------------------------------------------------------------------
275 
276     class string_cast_error : public error
277     {
278     public:
string_cast_error(const std::string & str)279         string_cast_error(const std::string& str):
280             error(ESTRING_CAST,"string cast error: invalid string = '" + str + "'") {}
281     };
282 
283     template <
284         typename T
285         >
286     struct string_cast_helper
287     {
288         template < typename charT, typename traits, typename alloc >
caststring_cast_helper289         static const T cast (
290             const std::basic_string<charT,traits,alloc>& str
291         )
292         {
293             using namespace std;
294             basic_istringstream<charT,traits,alloc> sin(str);
295             T temp;
296             sin >> temp;
297             if (!sin) throw string_cast_error(narrow(str));
298             if (sin.get() != std::char_traits<charT>::eof()) throw string_cast_error(narrow(str));
299             return temp;
300         }
301     };
302 
303     template <typename C, typename T, typename A>
304     struct string_cast_helper<std::basic_string<C,T,A> >
305     {
306         template < typename charT, typename traits, typename alloc >
307         static const std::basic_string<C,T,A> cast (
308             const std::basic_string<charT,traits,alloc>& str
309         )
310         {
311             std::basic_string<C,T,A> temp;
312             temp.resize(str.size());
313             for (unsigned long i = 0; i < str.size(); ++i)
314                 temp[i] = zero_extend_cast<C>(str[i]);
315             return temp;
316         }
317     };
318 
319     template <>
320     struct string_cast_helper<bool>
321     {
322         template < typename charT, typename traits, typename alloc >
323         static bool cast (
324             const std::basic_string<charT,traits,alloc>& str
325         )
326         {
327             using namespace std;
328             if (str.size() == 1 && str[0] == '1')
329                 return true;
330             if (str.size() == 1 && str[0] == '0')
331                 return false;
332             if (tolower(narrow(str)) == "true")
333                 return true;
334             if (tolower(narrow(str)) == "false")
335                 return false;
336 
337             throw string_cast_error(narrow(str));
338         }
339     };
340 
341 #define DLIB_STRING_CAST_INTEGRAL(type)                             \
342     template <>                                                     \
343     struct string_cast_helper<type>                                 \
344     {                                                               \
345         template < typename charT, typename traits, typename alloc> \
346         static type cast (                                    \
347             const std::basic_string<charT,traits,alloc>& str        \
348         )                                                           \
349         {                                                           \
350             using namespace std;                                    \
351             basic_istringstream<charT,traits,alloc> sin(str);       \
352             type temp;                                              \
353             if (str.size() > 2 && str[0] == _dT(charT,'0') && str[1] == _dT(charT,'x'))   \
354                 sin >> hex >> temp;                                 \
355             else                                                    \
356                 sin >> temp;                                        \
357             if (!sin) throw string_cast_error(narrow(str));                 \
358             if (sin.get() != std::char_traits<charT>::eof()) throw string_cast_error(narrow(str));     \
359             return temp;                                            \
360         }                                                           \
361     };
362 
363     DLIB_STRING_CAST_INTEGRAL(unsigned short)
364     DLIB_STRING_CAST_INTEGRAL(short)
365     DLIB_STRING_CAST_INTEGRAL(unsigned int)
366     DLIB_STRING_CAST_INTEGRAL(int)
367     DLIB_STRING_CAST_INTEGRAL(unsigned long)
368     DLIB_STRING_CAST_INTEGRAL(long)
369     DLIB_STRING_CAST_INTEGRAL(uint64)
370 
371     template <
372         typename T,
373         typename charT,
374         typename traits,
375         typename alloc
376         >
377     inline const T string_cast (
378         const std::basic_string<charT,traits,alloc>& str
379     )
380     {
381         COMPILE_TIME_ASSERT(is_pointer_type<T>::value == false);
382         return string_cast_helper<T>::cast(str);
383     }
384 
385     template <typename T>
386     inline const T string_cast (const char* str){ return string_cast<T>(std::string(str)); }
387     template <typename T>
388     inline const T string_cast (const wchar_t* str){ return string_cast<T>(std::wstring(str)); }
389 
390 // ----------------------------------------------------------------------------------------
391 
392     class string_assign
393     {
394         template <
395             typename charT,
396             typename traits,
397             typename alloc
398             >
399         class string_assign_helper
400         {
401         public:
402             string_assign_helper (
403                 const std::basic_string<charT,traits,alloc>& str_
404             ) : str(str_) {}
405 
406             template <typename T>
407             operator T () const
408             {
409                 return string_cast<T>(str);
410             }
411 
412         private:
413 
414             const std::basic_string<charT,traits,alloc>& str;
415         };
416 
417     // -------------
418 
419         class char_assign_helper
420         {
421         public:
422             char_assign_helper (
423                 const char* str_
424             ) : str(str_) {}
425 
426             template <typename T>
427             operator T () const
428             {
429                 return string_cast<T>(str);
430             }
431 
432         private:
433 
434             const char* str;
435         };
436 
437     // -------------
438 
439         class wchar_t_assign_helper
440         {
441         public:
442             wchar_t_assign_helper (
443                 const wchar_t* str_
444             ) : str(str_) {}
445 
446             template <typename T>
447             operator T () const
448             {
449                 return string_cast<T>(str);
450             }
451 
452         private:
453 
454             const wchar_t* str;
455         };
456 
457     // -------------
458 
459     public:
460 
461         template <
462             typename charT,
463             typename traits,
464             typename alloc
465             >
466         string_assign_helper<charT,traits,alloc> operator=(
467             const std::basic_string<charT,traits,alloc>& str
468         ) const
469         {
470             return string_assign_helper<charT,traits,alloc>(str);
471         }
472 
473         char_assign_helper operator= (
474             const char* str
475         ) const
476         {
477             return char_assign_helper(str);
478         }
479 
480         wchar_t_assign_helper operator= (
481             const wchar_t* str
482         ) const
483         {
484             return wchar_t_assign_helper(str);
485         }
486     };
487 
488     const string_assign sa = string_assign();
489 
490 // ----------------------------------------------------------------------------------------
491 
492     template <
493         typename charT,
494         typename traits,
495         typename alloc
496         >
497     const std::basic_string<charT,traits,alloc> wrap_string (
498         const std::basic_string<charT,traits,alloc>& str,
499         const unsigned long first_pad = 0,
500         const unsigned long rest_pad = 0,
501         const unsigned long max_per_line = 79
502     )
503     {
504         DLIB_ASSERT ( first_pad < max_per_line && rest_pad < max_per_line &&
505                  rest_pad >= first_pad,
506                  "\tconst std::basic_string<charT,traits,alloc> wrap_string()"
507                  << "\n\tfirst_pad:    " << first_pad
508                  << "\n\trest_pad:     " << rest_pad
509                  << "\n\tmax_per_line: " << max_per_line  );
510 
511         using namespace std;
512 
513         basic_ostringstream<charT,traits,alloc> sout;
514         basic_istringstream<charT,traits,alloc> sin(str);
515 
516         for (unsigned long i = 0; i < rest_pad; ++i)
517             sout << _dT(charT," ");
518         const basic_string<charT,traits,alloc> pad(sout.str());
519         sout.str(_dT(charT,""));
520 
521         for (unsigned long i = 0; i < first_pad; ++i)
522             sout << _dT(charT," ");
523 
524 
525         typename basic_string<charT,traits,alloc>::size_type remaining = max_per_line - rest_pad;
526 
527         basic_string<charT,traits,alloc> temp;
528 
529         sin >> temp;
530         while (sin)
531         {
532             if (temp.size() > remaining)
533             {
534                 if (temp.size() + rest_pad >= max_per_line)
535                 {
536                     string::size_type i = 0;
537                     for (; i < temp.size(); ++i)
538                     {
539                         sout << temp[i];
540                         --remaining;
541                         if (remaining == 0)
542                         {
543                             sout << _dT(charT,"\n") << pad;
544                             remaining = max_per_line - rest_pad;
545                         }
546                     }
547                 }
548                 else
549                 {
550                     sout << _dT(charT,"\n") << pad << temp;
551                     remaining = max_per_line - rest_pad - temp.size();
552                 }
553             }
554             else if (temp.size() == remaining)
555             {
556                 sout << temp;
557                 remaining = 0;
558             }
559             else
560             {
561                 sout << temp;
562                 remaining -= temp.size();
563             }
564 
565             sin >> temp;
566             if (remaining == 0 && sin)
567             {
568                 sout << _dT(charT,"\n") << pad;
569                 remaining = max_per_line - rest_pad;
570             }
571             else
572             {
573                 sout << _dT(charT," ");
574                 --remaining;
575             }
576         }
577 
578         return sout.str();
579     }
580 
581     template <
582         typename charT
583         >
584     const std::basic_string<charT> wrap_string (
585         const charT* str,
586         const unsigned long first_pad = 0,
587         const unsigned long rest_pad = 0,
588         const unsigned long max_per_line = 79
589     ) { return wrap_string(std::basic_string<charT>(str),first_pad,rest_pad,max_per_line); }
590 
591 // ----------------------------------------------------------------------------------------
592 
593     template <
594         typename charT,
595         typename traits,
596         typename alloc
597         >
598     const std::basic_string<charT,traits,alloc> ltrim (
599         const std::basic_string<charT,traits,alloc>& str,
600         const std::basic_string<charT,traits,alloc>& trim_chars
601     )
602     {
603         typedef std::basic_string<charT,traits,alloc> string;
604         typename string::size_type pos = str.find_first_not_of(trim_chars);
605         if (pos != string::npos)
606             return str.substr(pos);
607         else
608             return std::basic_string<charT,traits,alloc>();
609     }
610 
611     template <
612         typename charT,
613         typename traits,
614         typename alloc
615         >
616     const std::basic_string<charT,traits,alloc> ltrim (
617         const std::basic_string<charT,traits,alloc>& str,
618         const charT* trim_chars = _dT(charT," \t\r\n")
619     ) { return ltrim(str,std::basic_string<charT,traits,alloc>(trim_chars)); }
620 
621 // ----------------------------------------------------------------------------------------
622 
623     template <
624         typename charT,
625         typename traits,
626         typename alloc
627         >
628     const std::basic_string<charT,traits,alloc> rtrim (
629         const std::basic_string<charT,traits,alloc>& str,
630         const std::basic_string<charT,traits,alloc>& trim_chars
631     )
632     {
633         typedef std::basic_string<charT,traits,alloc> string;
634 
635         typename string::size_type pos = str.find_last_not_of(trim_chars);
636         if (pos != string::npos)
637             return str.substr(0,pos+1);
638         else
639             return std::basic_string<charT,traits,alloc>();
640     }
641 
642     template <
643         typename charT,
644         typename traits,
645         typename alloc
646         >
647     const std::basic_string<charT,traits,alloc> rtrim (
648         const std::basic_string<charT,traits,alloc>& str,
649         const charT* trim_chars = _dT(charT," \t\r\n")
650     ) { return rtrim(str,std::basic_string<charT,traits,alloc>(trim_chars)); }
651 
652 // ----------------------------------------------------------------------------------------
653 
654     template <
655         typename charT,
656         typename traits,
657         typename alloc
658         >
659     const std::basic_string<charT,traits,alloc> trim (
660         const std::basic_string<charT,traits,alloc>& str,
661         const std::basic_string<charT,traits,alloc>& trim_chars
662     )
663     {
664         typedef std::basic_string<charT,traits,alloc> string;
665         typename string::size_type lpos = str.find_first_not_of(trim_chars);
666         if (lpos != string::npos)
667         {
668             typename string::size_type rpos = str.find_last_not_of(trim_chars);
669             return str.substr(lpos,rpos-lpos+1);
670         }
671         else
672         {
673             return std::basic_string<charT,traits,alloc>();
674         }
675     }
676 
677     template <
678         typename charT,
679         typename traits,
680         typename alloc
681         >
682     const std::basic_string<charT,traits,alloc> trim (
683         const std::basic_string<charT,traits,alloc>& str,
684         const charT* trim_chars = _dT(charT," \t\r\n")
685     ) { return trim(str,std::basic_string<charT,traits,alloc>(trim_chars)); }
686 
687 // ----------------------------------------------------------------------------------------
688 
689     template <
690         typename charT,
691         typename traits,
692         typename alloc
693         >
694     const std::basic_string<charT,traits,alloc> rpad (
695         const std::basic_string<charT,traits,alloc>& str,
696         long pad_length,
697         const std::basic_string<charT,traits,alloc>& pad_string
698     )
699     {
700         typedef std::basic_string<charT,traits,alloc> string;
701         // if str is too big then just return str
702         if (pad_length <= static_cast<long>(str.size()))
703             return str;
704 
705         // make the string we will padd onto the string
706         string P;
707         while (P.size() < pad_length - str.size())
708             P += pad_string;
709         P = P.substr(0,pad_length - str.size());
710 
711         // return the padded string
712         return str + P;
713     }
714 
715     template <
716         typename charT,
717         typename traits,
718         typename alloc
719         >
720     const std::basic_string<charT,traits,alloc> rpad (
721         const std::basic_string<charT,traits,alloc>& str,
722         long pad_length,
723         const charT* pad_string = _dT(charT," ")
724     ) { return rpad(str,pad_length,std::basic_string<charT,traits,alloc>(pad_string)); }
725 
726 // ----------------------------------------------------------------------------------------
727 
728     template <
729         typename charT,
730         typename traits,
731         typename alloc
732         >
733     const std::basic_string<charT,traits,alloc> lpad (
734         const std::basic_string<charT,traits,alloc>& str,
735         long pad_length,
736         const std::basic_string<charT,traits,alloc>& pad_string
737     )
738     {
739         typedef std::basic_string<charT,traits,alloc> string;
740         // if str is too big then just return str
741         if (pad_length <= static_cast<long>(str.size()))
742             return str;
743 
744         // make the string we will padd onto the string
745         string P;
746         while (P.size() < pad_length - str.size())
747             P += pad_string;
748         P = P.substr(0,pad_length - str.size());
749 
750         // return the padded string
751         return P + str;
752     }
753 
754     template <
755         typename charT,
756         typename traits,
757         typename alloc
758         >
759     const std::basic_string<charT,traits,alloc> lpad (
760         const std::basic_string<charT,traits,alloc>& str,
761         long pad_length,
762         const charT* pad_string = _dT(charT," ")
763     ) { return lpad(str,pad_length,std::basic_string<charT,traits,alloc>(pad_string)); }
764 
765 // ----------------------------------------------------------------------------------------
766 
767     template <
768         typename charT,
769         typename traits,
770         typename alloc
771         >
772     const std::basic_string<charT,traits,alloc> pad (
773         const std::basic_string<charT,traits,alloc>& str,
774         long pad_length,
775         const std::basic_string<charT,traits,alloc>& pad_string
776     )
777     {
778         const long str_size = static_cast<long>(str.size());
779         return rpad(lpad(str,(pad_length-str_size)/2 + str_size,pad_string),
780                     pad_length,
781                     pad_string);
782     }
783 
784     template <
785         typename charT,
786         typename traits,
787         typename alloc
788         >
789     const std::basic_string<charT,traits,alloc> pad (
790         const std::basic_string<charT,traits,alloc>& str,
791         long pad_length,
792         const charT* pad_string = _dT(charT," ")
793     ) { return pad(str,pad_length,std::basic_string<charT,traits,alloc>(pad_string)); }
794 
795 // ----------------------------------------------------------------------------------------
796 
797     template <
798         typename charT,
799         typename traits,
800         typename alloc
801         >
802     const std::basic_string<charT,traits,alloc> left_substr (
803         const std::basic_string<charT,traits,alloc>& str,
804         const std::basic_string<charT,traits,alloc>& delim
805     )
806     {
807         return str.substr(0,str.find_first_of(delim));
808     }
809 
810     template <
811         typename charT,
812         typename traits,
813         typename alloc
814         >
815     const std::basic_string<charT,traits,alloc> left_substr (
816         const std::basic_string<charT,traits,alloc>& str,
817         const charT* delim = _dT(charT," \n\r\t")
818     )
819     {
820         return str.substr(0,str.find_first_of(delim));
821     }
822 
823 // ----------------------------------------------------------------------------------------
824 
825     template <
826         typename charT,
827         typename traits,
828         typename alloc
829         >
830     const std::basic_string<charT,traits,alloc> right_substr (
831         const std::basic_string<charT,traits,alloc>& str,
832         const std::basic_string<charT,traits,alloc>& delim
833     )
834     {
835         typename std::basic_string<charT,traits,alloc>::size_type delim_pos = str.find_last_of(delim);
836         if (delim_pos != std::basic_string<charT,traits,alloc>::npos)
837             return str.substr(delim_pos+1);
838         else
839             return _dT(charT,"");
840     }
841 
842     template <
843         typename charT,
844         typename traits,
845         typename alloc
846         >
847     const std::basic_string<charT,traits,alloc> right_substr (
848         const std::basic_string<charT,traits,alloc>& str,
849         const charT* delim = _dT(charT," \n\r\t")
850     )
851     {
852         typename std::basic_string<charT,traits,alloc>::size_type delim_pos = str.find_last_of(delim);
853         if (delim_pos != std::basic_string<charT,traits,alloc>::npos)
854             return str.substr(delim_pos+1);
855         else
856             return _dT(charT,"");
857     }
858 
859 // ----------------------------------------------------------------------------------------
860 
861     template <
862         typename charT,
863         typename traits,
864         typename alloc
865         >
866     std::pair<std::basic_string<charT,traits,alloc>, std::basic_string<charT,traits,alloc> >
867     split_on_first (
868         const std::basic_string<charT,traits,alloc>& str,
869         const charT* delim = _dT(charT," \n\r\t")
870     )
871     {
872         typename std::basic_string<charT,traits,alloc>::size_type delim_pos = str.find_first_of(delim);
873         if (delim_pos != std::basic_string<charT,traits,alloc>::npos)
874             return std::make_pair(str.substr(0, delim_pos), str.substr(delim_pos+1));
875         else
876             return std::make_pair(str, _dT(charT,""));
877     }
878 
879     template <
880         typename charT,
881         typename traits,
882         typename alloc
883         >
884     inline std::pair<std::basic_string<charT,traits,alloc>, std::basic_string<charT,traits,alloc> >
885     split_on_first (
886         const std::basic_string<charT,traits,alloc>& str,
887         const std::basic_string<charT,traits,alloc>& delim
888     )
889     {
890         return split_on_first(str, delim.c_str());
891     }
892 
893 // ----------------------------------------------------------------------------------------
894 
895     template <
896         typename charT,
897         typename traits,
898         typename alloc
899         >
900     std::pair<std::basic_string<charT,traits,alloc>, std::basic_string<charT,traits,alloc> >
901     split_on_last (
902         const std::basic_string<charT,traits,alloc>& str,
903         const charT* delim = _dT(charT," \n\r\t")
904     )
905     {
906         typename std::basic_string<charT,traits,alloc>::size_type delim_pos = str.find_last_of(delim);
907         if (delim_pos != std::basic_string<charT,traits,alloc>::npos)
908             return std::make_pair(str.substr(0, delim_pos), str.substr(delim_pos+1));
909         else
910             return std::make_pair(str, _dT(charT,""));
911     }
912 
913     template <
914         typename charT,
915         typename traits,
916         typename alloc
917         >
918     inline std::pair<std::basic_string<charT,traits,alloc>, std::basic_string<charT,traits,alloc> >
919     split_on_last (
920         const std::basic_string<charT,traits,alloc>& str,
921         const std::basic_string<charT,traits,alloc>& delim
922     )
923     {
924         return split_on_last(str, delim.c_str());
925     }
926 
927 // ----------------------------------------------------------------------------------------
928 
929     template <
930         typename charT,
931         typename traits,
932         typename alloc
933         >
934     const std::vector<std::basic_string<charT,traits,alloc> > split (
935         const std::basic_string<charT,traits,alloc>& str,
936         const charT* delim = _dT(charT," \n\r\t")
937     )
938     {
939         std::basic_string<charT,traits,alloc> temp;
940 
941         std::vector<std::basic_string<charT,traits,alloc> > res;
942 
943         for (unsigned long i = 0; i < str.size(); ++i)
944         {
945             // check if delim contains the character str[i]
946             bool hit = false;
947             const charT* d = delim;
948             while (*d != '\0')
949             {
950                 if (str[i] == *d)
951                 {
952                     hit = true;
953                     break;
954                 }
955                 ++d;
956             }
957 
958             if (hit)
959             {
960                 if (temp.size() != 0)
961                 {
962                     res.push_back(temp);
963                     temp.clear();
964                 }
965             }
966             else
967             {
968                 temp.push_back(str[i]);
969             }
970         }
971 
972         if (temp.size() != 0)
973             res.push_back(temp);
974 
975         return res;
976     }
977 
978     template <
979         typename charT,
980         typename traits,
981         typename alloc
982         >
983     const std::vector<std::basic_string<charT,traits,alloc> > split (
984         const std::basic_string<charT,traits,alloc>& str,
985         const std::basic_string<charT,traits,alloc>& delim
986     )
987     {
988         return split(str,delim.c_str());
989     }
990 
991     inline const std::vector<std::string> split (
992         const char* str,
993         const char* delim = " \n\r\t"
994     )
995     {
996         return split(std::string(str),delim);
997     }
998 
999 // ----------------------------------------------------------------------------------------
1000 
1001 }
1002 
1003 #endif // DLIB_STRINg_
1004 
1005