Fixed split to allow empty parts in beginning and end of string
[libs/core.git] / source / utils.cpp
1 #include <list>
2 #include "utils.h"
3
4 using namespace std;
5
6 namespace Msp {
7
8 /**
9 Compares two strings, ignoring case.
10
11 @param   s1  First string
12 @param   s2  Second string
13
14 @return  -1 if s1<s2, 0 if s1==s2, 1 if s1>s2
15 */
16 int strcasecmp(const string &s1, const string &s2)
17 {
18         string::const_iterator i1=s1.begin();
19         string::const_iterator i2=s2.begin();
20         for(; (i1!=s1.end() && i2!=s2.end()); ++i1, ++i2)
21         {
22                 const char c1=::tolower(*i1);
23                 const char c2=::tolower(*i2);
24                 if(c1!=c2) return c1-c2;
25         }
26         if(i1!=s1.end()) return *i1;
27         if(i2!=s2.end()) return -*i2;
28         return 0;
29 }
30
31 /**
32 Returns a lowercase copy of the given string.
33 */
34 string tolower(const string &str)
35 {
36         string result(str);
37         transform(result.begin(), result.end(), result.begin(), ::tolower);
38         return result;
39 }
40
41 /**
42 Returns an uppercase copy of the given string.
43 */
44 string toupper(const string &str)
45 {
46         string result(str);
47         transform(result.begin(), result.end(), result.begin(), ::toupper);
48         return result;
49 }
50
51 /**
52 Splits a string to parts.
53
54 @param   str          String to be split
55 @param   sep          A set of separator characters
56 @param   allow_empty  Whether or not to produce empty parts for sequences of
57                       more than one separator character
58 */
59 vector<string> split(const string &str, const string &sep, bool allow_empty)
60 {
61         vector<string> result;
62         
63         unsigned start=0;
64         if(!allow_empty)
65                 start=str.find_first_not_of(sep);
66         
67         while(start<str.size())
68         {
69                 unsigned end=str.find_first_of(sep, start);
70                 result.push_back(str.substr(start, end-start));
71                 
72                 if(end==string::npos)
73                         break;
74                 
75                 if(allow_empty)
76                 {
77                         start=end+1;
78                         if(start==str.size())
79                                 result.push_back(string());
80                 }
81                 else
82                         start=str.find_first_not_of(sep, end);
83         }
84
85         return result;
86 }
87
88 vector<string> split(const string &str, char sep, bool allow_empty)
89 {
90         return split(str, string(1, sep), allow_empty);
91 }
92
93 /**
94 Builds a single string from the strings in the given sequence by concatenating
95 them.
96
97 @param  seq  A sequence of strings
98 @param  sep  Separator to be inserted between strings
99 */
100 template<typename T>
101 string join(const T &seq, const string &sep)
102 {
103         string result;
104         for(typename T::const_iterator i=seq.begin(); i!=seq.end(); ++i)
105         {
106                 if(i!=seq.begin())
107                         result+=sep;
108                 result+=*i;
109         }
110
111         return result;
112 }
113 template string join<list<string> >(const list<string> &, const string &);
114 template string join<vector<string> >(const vector<string> &, const string &);
115
116 /**
117 Returns a copy of the given string with leading and trailing whitespace
118 removed.
119 */
120 string strip(const string &s)
121 {
122         string result=s;
123         if(!result.erase(0, result.find_first_not_of(" \t\n")).empty())
124                 result.erase(result.find_last_not_of(" \t\n")+1);
125         return result;
126 }
127
128 } // namespace Msp