src/string.cpp

changeset 119
bdf8d46c145f
child 128
186ebeea2a85
equal deleted inserted replaced
118:e3361cf7cbf4 119:bdf8d46c145f
1 /*
2 Copyright 2012-2014 Santeri Piippo
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 2. Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in the
13 documentation and/or other materials provided with the distribution.
14 3. The name of the author may not be used to endorse or promote products
15 derived from this software without specific prior written permission.
16
17 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <cstring>
30 #include "main.h"
31 #include "string.h"
32
33 // =============================================================================
34 //
35 int String::compare (const String& other) const
36 {
37 return m_string.compare (other.stdString());
38 }
39
40 // =============================================================================
41 //
42 void String::trim (int n)
43 {
44 if (n > 0)
45 m_string = mid (0, length() - n).stdString();
46 else
47 m_string = mid (n, -1).stdString();
48 }
49
50 // =============================================================================
51 //
52 String String::strip (const List< char >& unwanted)
53 {
54 String copy (m_string);
55
56 for (char c : unwanted)
57 for (int i = 0; i < copy.length(); ++i)
58 if (copy[i] == c)
59 copy.removeAt (i);
60
61 /*
62 int pos = 0;
63 while ((pos = copy.First (c)) != -1)
64 copy.RemoveAt (pos--);
65 */
66
67 return copy;
68 }
69
70 // =============================================================================
71 //
72 String String::toUppercase() const
73 {
74 String newstr = m_string;
75
76 for (char& c : newstr)
77 if (c >= 'a' && c <= 'z')
78 c -= 'a' - 'A';
79
80 return newstr;
81 }
82
83 // =============================================================================
84 //
85 String String::toLowercase() const
86 {
87 String newstr = m_string;
88
89 for (char & c : newstr)
90 if (c >= 'A' && c <= 'Z')
91 c += 'a' - 'A';
92
93 return newstr;
94 }
95
96 // =============================================================================
97 //
98 StringList String::split (char del) const
99 {
100 String delimstr;
101 delimstr += del;
102 return split (delimstr);
103 }
104
105 // =============================================================================
106 //
107 StringList String::split (const String& del) const
108 {
109 StringList res;
110 long a = 0;
111
112 // Find all separators and store the text left to them.
113 for (;;)
114 {
115 long b = firstIndexOf (del, a);
116
117 if (b == -1)
118 break;
119
120 String sub = mid (a, b);
121
122 if (sub.length() > 0)
123 res.append (mid (a, b));
124
125 a = b + del.length();
126 }
127
128 // Add the string at the right of the last separator
129 if (a < (int) length())
130 res.append (mid (a, length()));
131
132 return res;
133 }
134
135 // =============================================================================
136 //
137 void String::replace (const char* a, const char* b)
138 {
139 long pos;
140
141 while ((pos = firstIndexOf (a)) != -1)
142 m_string = m_string.replace (pos, strlen (a), b);
143 }
144
145 // =============================================================================
146 //
147 int String::count (char needle) const
148 {
149 int needles = 0;
150
151 for (const char & c : m_string)
152 if (c == needle)
153 needles++;
154
155 return needles;
156 }
157
158 // =============================================================================
159 //
160 String String::mid (long a, long b) const
161 {
162 if (b == -1)
163 b = length();
164
165 if (b == a)
166 return "";
167
168 if (b < a)
169 {
170 // Swap the variables
171 int c = a;
172 a = b;
173 b = c;
174 }
175
176 char* newstr = new char[b - a + 1];
177 strncpy (newstr, m_string.c_str() + a, b - a);
178 newstr[b - a] = '\0';
179
180 String other (newstr);
181 delete[] newstr;
182 return other;
183 }
184
185 // =============================================================================
186 //
187 int String::wordPosition (int n) const
188 {
189 int count = 0;
190
191 for (int i = 0; i < length(); ++i)
192 {
193 if (m_string[i] != ' ')
194 continue;
195
196 if (++count < n)
197 continue;
198
199 return i;
200 }
201
202 return -1;
203 }
204
205 // =============================================================================
206 //
207 int String::firstIndexOf (const char* c, int a) const
208 {
209 for (; a < length(); a++)
210 if (m_string[a] == c[0] && strncmp (m_string.c_str() + a, c, strlen (c)) == 0)
211 return a;
212
213 return -1;
214 }
215
216 // =============================================================================
217 //
218 int String::lastIndexOf (const char* c, int a) const
219 {
220 if (a == -1 || a >= length())
221 a = length() - 1;
222
223 for (; a > 0; a--)
224 if (m_string[a] == c[0] && strncmp (m_string.c_str() + a, c, strlen (c)) == 0)
225 return a;
226
227 return -1;
228 }
229
230 // =============================================================================
231 //
232 void String::dump() const
233 {
234 print ("`%1`:\n", chars());
235 int i = 0;
236
237 for (char u : m_string)
238 print ("\t%1. [%d2] `%3`\n", i++, u, String (u));
239 }
240
241 // =============================================================================
242 //
243 long String::toLong (bool* ok, int base) const
244 {
245 errno = 0;
246 char* endptr;
247 long i = strtol (m_string.c_str(), &endptr, base);
248
249 if (ok)
250 *ok = (errno == 0 && *endptr == '\0');
251
252 return i;
253 }
254
255 // =============================================================================
256 //
257 float String::toFloat (bool* ok) const
258 {
259 errno = 0;
260 char* endptr;
261 float i = strtof (m_string.c_str(), &endptr);
262
263 if (ok)
264 *ok = (errno == 0 && *endptr == '\0');
265
266 return i;
267 }
268
269 // =============================================================================
270 //
271 double String::toDouble (bool* ok) const
272 {
273 errno = 0;
274 char* endptr;
275 double i = strtod (m_string.c_str(), &endptr);
276
277 if (ok)
278 *ok = (errno == 0 && *endptr == '\0');
279
280 return i;
281 }
282
283 // =============================================================================
284 //
285 String String::operator+ (const String& data) const
286 {
287 String newString = *this;
288 newString.append (data);
289 return newString;
290 }
291
292 // =============================================================================
293 //
294 String String::operator+ (const char* data) const
295 {
296 String newstr = *this;
297 newstr.append (data);
298 return newstr;
299 }
300
301 // =============================================================================
302 //
303 bool String::isNumeric() const
304 {
305 bool gotDot = false;
306
307 for (const char & c : m_string)
308 {
309 // Allow leading hyphen for negatives
310 if (&c == &m_string[0] && c == '-')
311 continue;
312
313 // Check for decimal point
314 if (!gotDot && c == '.')
315 {
316 gotDot = true;
317 continue;
318 }
319
320 if (c >= '0' && c <= '9')
321 continue; // Digit
322
323 // If the above cases didn't catch this character, it was
324 // illegal and this is therefore not a number.
325 return false;
326 }
327
328 return true;
329 }
330
331 // =============================================================================
332 //
333 bool String::endsWith (const String& other)
334 {
335 if (length() < other.length())
336 return false;
337
338 const int ofs = length() - other.length();
339 return strncmp (chars() + ofs, other.chars(), other.length()) == 0;
340 }
341
342 // =============================================================================
343 //
344 bool String::startsWith (const String& other)
345 {
346 if (length() < other.length())
347 return false;
348
349 return strncmp (chars(), other.chars(), other.length()) == 0;
350 }
351
352 // =============================================================================
353 //
354 void String::sprintf (const char* fmtstr, ...)
355 {
356 char* buf;
357 int bufsize = 256;
358 va_list va;
359 va_start (va, fmtstr);
360
361 do
362 buf = new char[bufsize];
363 while (vsnprintf (buf, bufsize, fmtstr, va) >= bufsize);
364
365 va_end (va);
366 m_string = buf;
367 delete[] buf;
368 }
369
370 // =============================================================================
371 //
372 String StringList::join (const String& delim)
373 {
374 String result;
375
376 for (const String& it : deque())
377 {
378 if (result.isEmpty() == false)
379 result += delim;
380
381 result += it;
382 }
383
384 return result;
385 }
386
387 // =============================================================================
388 //
389 bool String::maskAgainst (const String& pattern) const
390 {
391 // Elevate to uppercase for case-insensitive matching
392 String pattern_upper = pattern.toUppercase();
393 String this_upper = toUppercase();
394 const char* maskstring = pattern_upper.chars();
395 const char* mptr = &maskstring[0];
396
397 for (const char* sptr = this_upper.chars(); *sptr != '\0'; sptr++)
398 {
399 if (*mptr == '?')
400 {
401 if (*(sptr + 1) == '\0')
402 {
403 // ? demands that there's a character here and there wasn't.
404 // Therefore, mask matching fails
405 return false;
406 }
407 }
408 elif (*mptr == '*')
409 {
410 char end = *(++mptr);
411
412 // If '*' is the final character of the message, all of the remaining
413 // string matches against the '*'. We don't need to bother checking
414 // the string any further.
415 if (end == '\0')
416 return true;
417
418 // Skip to the end character
419 while (*sptr != end && *sptr != '\0')
420 sptr++;
421
422 // String ended while the mask still had stuff
423 if (*sptr == '\0')
424 return false;
425 }
426 elif (*sptr != *mptr)
427 return false;
428
429 mptr++;
430 }
431
432 return true;
433 }
434
435 // =============================================================================
436 //
437 String String::fromNumber (int a)
438 {
439 char buf[32];
440 ::sprintf (buf, "%d", a);
441 return String (buf);
442 }
443
444 // =============================================================================
445 //
446 String String::fromNumber (long a)
447 {
448 char buf[32];
449 ::sprintf (buf, "%ld", a);
450 return String (buf);
451 }

mercurial