1 /*=========================================================================
2 *
3 * Copyright Insight Software Consortium
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0.txt
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 *=========================================================================*/
18
19 #include "itkStringTools.h"
20
21 #include <algorithm> // std::transform()
22 #include <cctype> // std::toupper(), std::tolower()
23
24 namespace itk
25 {
26
27 /////////////////////////////////////////////////////////////////////////////
28 // helper functions for string manipulations
29 /////////////////////////////////////////////////////////////////////////////
30
31 /** Method to trim the spaces or user-specified characters on both ends of a string. */
32 std::string&
Trim(std::string & str,const std::string & dislike)33 StringTools::Trim( std::string& str, const std::string& dislike )
34 {
35 return StringTools::TrimRight(StringTools::TrimLeft(str, dislike), dislike);
36 }
37
38 /** Method to trim the spaces or user-specified characters on left end of a string. */
39 std::string&
TrimLeft(std::string & str,const std::string & dislike)40 StringTools::TrimLeft( std::string& str, const std::string& dislike )
41 {
42 if ( !str.empty() )
43 {
44 std::string::size_type pos = str.find_first_not_of( dislike );
45 if ( pos != std::string::npos )
46 {
47 if ( pos > 0 )
48 {
49 str.erase( 0, pos );
50 }
51 }
52 else
53 {
54 str.clear();
55 }
56 }
57
58 return str;
59 }
60
61 /** Method to trim the spaces or user-specified characters on right end of a string. */
62 std::string&
TrimRight(std::string & str,const std::string & dislike)63 StringTools::TrimRight( std::string& str, const std::string& dislike )
64 {
65 if ( !str.empty() )
66 {
67 std::string::size_type pos = str.find_last_not_of( dislike );
68 if ( pos != std::string::npos )
69 {
70 if ( (++pos) < str.size() )
71 {
72 str.erase( pos );
73 }
74 }
75 else
76 {
77 str.clear();
78 }
79 }
80
81 return str;
82 }
83
84 /** Method to covert lower-case characters to upper cases in a string. */
85 std::string&
ToUpperCase(std::string & str)86 StringTools::ToUpperCase( std::string& str )
87 {
88 // explicit cast needed to resolve ambiguity
89 std::transform( str.begin(), str.end(), str.begin(), (int(*)(int))std::toupper );
90 return str;
91 }
92
93 /** Method to covert upper-case characters to lower cases in a string. */
94 std::string&
ToLowerCase(std::string & str)95 StringTools::ToLowerCase( std::string& str )
96 {
97 // explicit cast needed to resolve ambiguity
98 std::transform( str.begin(), str.end(), str.begin(), (int(*)(int))std::tolower );
99 return str;
100 }
101
102 /** Method to split a string into two parts with user-defined delimiters. */
103 void
Split(const std::string & s,std::string & lpart,std::string & rpart,const std::string & delims)104 StringTools::Split( const std::string& s, std::string& lpart, std::string& rpart, const std::string& delims )
105 {
106 std::string::size_type pos = s.find_first_of( delims );
107 if ( pos != std::string::npos )
108 {
109 lpart = s.substr( 0, pos );
110 StringTools::Trim( lpart );
111 rpart = s.substr( pos + 1 );
112 StringTools::Trim( rpart );
113 }
114 else
115 {
116 lpart = s;
117 StringTools::Trim( lpart );
118 rpart = "";
119 }
120 }
121
122 /** Method to split a string into a sequence of strings with user-defined delimiters. */
123 void
Split(const std::string & s,std::vector<std::string> & result,const std::string & delims)124 StringTools::Split( const std::string& s, std::vector<std::string>& result, const std::string& delims )
125 {
126 std::string str = s;
127 while ( !str.empty() )
128 {
129 std::string::size_type pos = str.find_first_of( delims );
130 if ( pos != std::string::npos )
131 {
132 std::string front = str.substr( 0, pos );
133 StringTools::Trim( front );
134 result.push_back( front );
135 str = str.substr( pos+1 );
136 }
137 else
138 {
139 StringTools::Trim( str );
140 result.push_back( str );
141 str = ""; // no more text to split
142 }
143 }
144 }
145
146 /**
147 * Method to split a string into a sequence of sub-strings with user-defined delimiters,
148 * then each sub-string is further splitted into a <key,value> pair with separators "=:".
149 */
150 void
Split(const std::string & s,std::map<std::string,std::string> & result,const std::string & delims)151 StringTools::Split( const std::string& s, std::map<std::string,std::string>& result, const std::string& delims )
152 {
153 std::vector<std::string> items;
154 Split( s, items, delims );
155
156 for (const auto & item : items)
157 {
158 std::string value;
159 std::string key;
160 StringTools::Split( item, key, value );
161 result[key] = value;
162 }
163 }
164
165 /** Method to test whether one string matches with another. */
166 bool
MatchWith(const std::string & s1,const std::string & s2,bool ignoreCase)167 StringTools::MatchWith( const std::string& s1, const std::string& s2, bool ignoreCase )
168 {
169 // compare ignoring case
170 if ( ignoreCase )
171 {
172 // s1 to lower case
173 std::string ls1 = s1;
174 ToLowerCase( ls1 );
175 // s2 to lower case
176 std::string ls2 = s2;
177 ToLowerCase( ls2 );
178 // compare the two
179 if ( ls1 == ls2 )
180 {
181 return true;
182 }
183 else
184 {
185 return false;
186 }
187 }
188
189 // compare considering case
190 if ( s1 == s2 )
191 {
192 return true;
193 }
194 else
195 {
196 return false;
197 }
198 }
199
200 /** Method to test whether a string starts with a user-given sub-string. */
201 bool
StartWith(const std::string & s1,const std::string & s2,bool ignoreCase)202 StringTools::StartWith( const std::string& s1, const std::string& s2, bool ignoreCase )
203 {
204 // if case is not important
205 if ( ignoreCase )
206 {
207 // s1 to lower case
208 std::string ls1 = s1;
209 ToLowerCase( ls1 );
210 // s2 to lower case
211 std::string ls2 = s2;
212 ToLowerCase( ls2 );
213 // do the check
214 if ( ls1.find(ls2) == 0 )
215 {
216 return true;
217 }
218 else
219 {
220 return false;
221 }
222 }
223
224 // if case must be considered
225 if ( s1.find(s2) == 0 )
226 {
227 return true;
228 }
229 else
230 {
231 return false;
232 }
233 }
234
235 /** Method to test whether a string ends with a user-given sub-string. */
236 bool
EndWith(const std::string & s1,const std::string & s2,bool ignoreCase)237 StringTools::EndWith( const std::string& s1, const std::string& s2, bool ignoreCase )
238 {
239 std::string::size_type pos = s1.size() - s2.size();
240
241 // if case is not important
242 if ( ignoreCase )
243 {
244 // s1 to lower case
245 std::string ls1 = s1;
246 ToLowerCase( ls1 );
247 // s2 to lower case
248 std::string ls2 = s2;
249 ToLowerCase( ls2 );
250 // do the check
251 if ( ls1.rfind(ls2) == pos )
252 {
253 return true;
254 }
255 else
256 {
257 return false;
258 }
259 }
260
261 // if case must be considered
262 if ( s1.rfind(s2) == pos )
263 {
264 return true;
265 }
266 else
267 {
268 return false;
269 }
270 }
271
272 /** Method to test whether a string contains a user-given sub-string. */
273 bool
ContainSub(const std::string & s1,const std::string & s2,bool ignoreCase)274 StringTools::ContainSub( const std::string& s1, const std::string& s2, bool ignoreCase )
275 {
276 // if case is not important
277 if ( ignoreCase )
278 {
279 // s1 to lower case
280 std::string ls1 = s1;
281 ToLowerCase( ls1 );
282 // s2 to lower case
283 std::string ls2 = s2;
284 ToLowerCase( ls2 );
285 // to the check
286 if ( ls1.find(ls2) != std::string::npos )
287 {
288 return true;
289 }
290 else
291 {
292 return false;
293 }
294 }
295
296 // if case must be considered
297 if ( s1.find(s2) != std::string::npos )
298 {
299 return true;
300 }
301 else
302 {
303 return false;
304 }
305 }
306
307 } // namespace itk
308