]> git.tdb.fi Git - libs/core.git/blob - source/utils.cpp
Revamp the split functions to allow a max_split argument and splitting by longer...
[libs/core.git] / source / utils.cpp
1 /* $Id$
2
3 This file is part of libmspstrings
4 Copyright © 2006-2007 Mikko Rasa
5 Distributed under the LGPL
6 */
7
8 #include <list>
9 #include "utils.h"
10
11 using namespace std;
12
13 namespace {
14
15 template<bool long_sep, bool allow_empty>
16 vector<string> do_split(const string &str, const string &sep, int max_split)
17 {
18         vector<string> result;
19
20         unsigned start=0;
21         while(start<str.size())
22         {
23                 unsigned end=long_sep ? str.find(sep, start) : str.find_first_of(sep, start);
24                 if(end!=start || allow_empty)
25                 {
26                         if(max_split>=0 && result.size()==static_cast<unsigned>(max_split))
27                         {
28                                 result.push_back(str.substr(start));
29                                 break;
30                         }
31                         else
32                                 result.push_back(str.substr(start, end-start));
33                 }
34
35                 if(end>str.size())
36                         break;
37
38                 start=end+(long_sep ? sep.size() : 1);
39
40                 if(allow_empty && start==str.size())
41                         result.push_back(string());
42         }
43
44         return result;
45 }
46
47 }
48
49 namespace Msp {
50
51 /**
52 Compares two strings, ignoring case.
53
54 @param   s1  First string
55 @param   s2  Second string
56
57 @return  -1 if s1<s2, 0 if s1==s2, 1 if s1>s2
58 */
59 int strcasecmp(const string &s1, const string &s2)
60 {
61         string::const_iterator i1=s1.begin();
62         string::const_iterator i2=s2.begin();
63         for(; (i1!=s1.end() && i2!=s2.end()); ++i1, ++i2)
64         {
65                 const char c1=::tolower(*i1);
66                 const char c2=::tolower(*i2);
67                 if(c1!=c2) return c1-c2;
68         }
69         if(i1!=s1.end()) return *i1;
70         if(i2!=s2.end()) return -*i2;
71         return 0;
72 }
73
74 /**
75 Returns a lowercase copy of the given string.
76 */
77 string tolower(const string &str)
78 {
79         string result(str);
80         transform(result.begin(), result.end(), result.begin(), ::tolower);
81         return result;
82 }
83
84 /**
85 Returns an uppercase copy of the given string.
86 */
87 string toupper(const string &str)
88 {
89         string result(str);
90         transform(result.begin(), result.end(), result.begin(), ::toupper);
91         return result;
92 }
93
94 vector<string> split_fields(const string &str, const string &sep, int max_split)
95 {
96         return do_split<true, true>(str, sep, max_split);
97 }
98
99 vector<string> split_fields(const string &str, char sep, int max_split)
100 {
101         return split_fields(str, string(1, sep), max_split);
102 }
103
104 vector<string> split_long(const string &str, const string &sep, int max_split)
105 {
106         return do_split<true, false>(str, sep, max_split);
107 }
108
109 vector<string> split(const string &str, const string &sep, int max_split)
110 {
111         return do_split<false, false>(str, sep, max_split);
112 }
113
114 vector<string> split(const string &str, char sep, int max_split)
115 {
116         return split(str, string(1, sep), max_split);
117 }
118
119 /**
120 Splits a string to parts.
121
122 @param   str          String to be split
123 @param   sep          A set of separator characters
124 @param   allow_empty  Whether or not to produce empty parts for sequences of
125                       more than one separator character
126 */
127 vector<string> split(const string &str, const string &sep, bool allow_empty)
128 {
129         vector<string> result;
130         
131         unsigned start=0;
132         if(!allow_empty)
133                 start=str.find_first_not_of(sep);
134         
135         while(start<str.size())
136         {
137                 unsigned end=str.find_first_of(sep, start);
138                 result.push_back(str.substr(start, end-start));
139                 
140                 if(end==string::npos)
141                         break;
142                 
143                 if(allow_empty)
144                 {
145                         start=end+1;
146                         if(start==str.size())
147                                 result.push_back(string());
148                 }
149                 else
150                         start=str.find_first_not_of(sep, end);
151         }
152
153         return result;
154 }
155
156 vector<string> split(const string &str, char sep, bool allow_empty)
157 {
158         return split(str, string(1, sep), allow_empty);
159 }
160
161 /**
162 Builds a single string from the strings in the given sequence by concatenating
163 them.
164
165 @param  seq  A sequence of strings
166 @param  sep  Separator to be inserted between strings
167 */
168 template<typename T>
169 string join(const T &seq, const string &sep)
170 {
171         string result;
172         for(typename T::const_iterator i=seq.begin(); i!=seq.end(); ++i)
173         {
174                 if(i!=seq.begin())
175                         result+=sep;
176                 result+=*i;
177         }
178
179         return result;
180 }
181 template string join<list<string> >(const list<string> &, const string &);
182 template string join<vector<string> >(const vector<string> &, const string &);
183
184 /**
185 Returns a copy of the given string with leading and trailing whitespace
186 removed.
187 */
188 string strip(const string &s)
189 {
190         string result=s;
191         if(!result.erase(0, result.find_first_not_of(" \t\r\n")).empty())
192                 result.erase(result.find_last_not_of(" \t\r\n")+1);
193         return result;
194 }
195
196 } // namespace Msp