sources/mystring.cpp

changeset 147
12c93c4a137c
parent 145
d0aedc9be448
child 148
19e98695e584
equal deleted inserted replaced
146:81357dcd3da4 147:12c93c4a137c
33 #include "mystring.h" 33 #include "mystring.h"
34 #include "md5.h" 34 #include "md5.h"
35 35
36 BEGIN_ZFC_NAMESPACE 36 BEGIN_ZFC_NAMESPACE
37 37
38 // ------------------------------------------------------------------------------------------------- 38 /*!
39 // 39 * \brief Compares this string with another.
40 * \param other The string to compare with.
41 * \returns -1 if this string is lexicographically less than \c other,
42 * 0 if they are equal, or
43 * 1 if this string is lexicographically greater than \c other.
44 */
40 int String::compare (const String& other) const 45 int String::compare (const String& other) const
41 { 46 {
42 return m_string.compare (other.stdString()); 47 return m_string.compare (other.stdString());
43 } 48 }
44 49
45 // ------------------------------------------------------------------------------------------------- 50 /*!
46 // 51 * \brief Removes all instances of an unwanted character from this string.
47 void String::trim (int n) 52 * \param unwanted Character to remove.
48 { 53 */
49 if (n > 0) 54 void String::strip (char unwanted)
50 m_string = mid (0, length() - n).stdString(); 55 {
51 else 56 for (int pos = 0; (pos = find (unwanted)) != -1;)
52 m_string = mid (n, -1).stdString(); 57 removeAt (pos--);
53 } 58 }
54 59
55 // ------------------------------------------------------------------------------------------------- 60 /*!
56 // 61 * \brief Removes all instances of multiple characters from this string.
57 String String::strip (char unwanted) const 62 * \param unwanted Characters to remove.
58 { 63 */
59 String result (m_string); 64 void String::strip (const List<char>& unwanted)
60 65 {
61 for (int pos = 0; (pos = result.find (unwanted)) != -1;) 66 for (char character : unwanted)
62 result.removeAt (pos--); 67 strip(character);
63 68 }
64 return result; 69
65 } 70 /*!
66 71 * \returns an upper-case version of this string.
67 // ------------------------------------------------------------------------------------------------- 72 */
68 //
69 String String::strip (const List<char>& unwanted) const
70 {
71 String result (m_string);
72
73 for (String c : unwanted)
74 for (int pos = 0; (pos = result.find (c)) != -1;)
75 result.removeAt (pos--);
76
77 return result;
78 }
79
80 // -------------------------------------------------------------------------------------------------
81 //
82 String String::toUpperCase() const 73 String String::toUpperCase() const
83 { 74 {
84 String result (m_string); 75 String result (m_string);
85 76
86 for (char &ch : result) 77 for (char &ch : result)
90 } 81 }
91 82
92 return result; 83 return result;
93 } 84 }
94 85
95 // ------------------------------------------------------------------------------------------------- 86 /*!
96 // 87 * \returns a lower-case version of this string.
88 */
97 String String::toLowerCase() const 89 String String::toLowerCase() const
98 { 90 {
99 String result (m_string); 91 String result (m_string);
100 92
101 for (char &ch : result) 93 for (char &ch : result)
105 } 97 }
106 98
107 return result; 99 return result;
108 } 100 }
109 101
110 // ------------------------------------------------------------------------------------------------- 102 /*!
111 // 103 * \brief Splits this string using the provided delimeter.
112 StringList String::split (char del) const 104 * \param delimeter Delimeter to use for splitting.
113 { 105 * \returns a string list containing the split strings.
114 String delimstr; 106 */
115 delimstr += del; 107 StringList String::split (char delimeter) const
116 return split (delimstr); 108 {
117 } 109 String delimeterString;
118 110 delimeterString += delimeter;
119 // ------------------------------------------------------------------------------------------------- 111 return split (delimeterString);
120 // 112 }
121 StringList String::split (const String& del) const 113
122 { 114 /*!
123 StringList res; 115 * \brief Splits this string using the provided delimeter.
116 * \param delimeter Delimeter to use for splitting.
117 * \returns a string list containing the split strings.
118 */
119 StringList String::split (const String& delimeter) const
120 {
121 StringList result;
124 int a = 0; 122 int a = 0;
125 int b; 123 int b;
126 124
127 // Find all separators and store the text left to them. 125 // Find all separators and store the text left to them.
128 while ((b = find (del, a)) != -1) 126 while ((b = find (delimeter, a)) != -1)
129 { 127 {
130 String sub = mid (a, b); 128 String sub = mid (a, b);
131 129
132 if (sub.length() > 0) 130 if (sub.length() > 0)
133 res << sub; 131 result << sub;
134 132
135 a = b + del.length(); 133 a = b + delimeter.length();
136 } 134 }
137 135
138 // Add the string at the right of the last separator 136 // Add the string at the right of the last separator
139 if (a < (int) length()) 137 if (a < (int) length())
140 res.append (mid (a, length())); 138 result.append (mid (a, length()));
141 139
142 return res; 140 return result;
143 } 141 }
144 142
145 // ------------------------------------------------------------------------------------------------- 143 /*!
146 // 144 * \brief Replaces all instances of \c text with \c replacement.
147 void String::replace (const char* a, const char* b) 145 * \param text Text to replace away.
148 { 146 * \param replacement Text to replace \c text with.
149 long pos; 147 */
150 148 void String::replace (const char* text, const char* replacement)
151 while ((pos = find (a)) != -1) 149 {
152 m_string = m_string.replace (pos, strlen (a), b); 150 int position;
153 } 151
154 152 while ((position = find (text)) != -1)
155 // ------------------------------------------------------------------------------------------------- 153 m_string = m_string.replace (position, strlen (text), replacement);
156 // 154 }
157 int String::count (char needle) const 155
156 /*!
157 * \param character Character to count.
158 * \returns the amount of \c character found in the string.
159 */
160 int String::count (char character) const
158 { 161 {
159 int result = 0; 162 int result = 0;
160 163
161 for (char ch : *this) 164 for (char ch : *this)
162 { 165 {
163 if (ch == needle) 166 if (ch == character)
164 result++; 167 result++;
165 } 168 }
166 169
167 return result; 170 return result;
168 } 171 }
169 172
170 // ------------------------------------------------------------------------------------------------- 173 /*!
171 // 174 * \param a Starting index of the range.
172 // Returns a substring from [a, b) 175 * \param b Ending index of the range.
173 // 176 * \returns a sub-string containing all characters from \c a to \c b, not including the character at \c b.
174 String String::mid (int a, int b) const 177 */
175 { 178 String String::mid (int rangeBegin, int rangeEnd) const
176 a = max(a, 0); 179 {
177 b = min(b, length()); 180 modifyIndex(rangeBegin);
178 181 modifyIndex(rangeEnd);
179 if (b == -1) 182 rangeBegin = max(rangeBegin, 0);
180 b = length(); 183 rangeEnd = min(rangeEnd, length());
181 184
182 if (b <= a) 185 if (rangeEnd <= rangeBegin)
183 return ""; 186 return "";
184 else 187 else
185 return m_string.substr(a, b - a); 188 return m_string.substr(rangeBegin, rangeEnd - rangeBegin);
186 } 189 }
187 190
188 // ------------------------------------------------------------------------------------------------- 191 /*!
189 // 192 * \param length Amount of characters to return.
193 * \returns the \c length right-most characters of the string.
194 */
190 String String::right(int length) const 195 String String::right(int length) const
191 { 196 {
192 if (length >= this->length()) 197 if (length >= this->length())
193 return *this; 198 return *this;
194 else 199 else
195 return String(chars() + this->length() - length); 200 return String(chars() + this->length() - length);
196 } 201 }
197 202
198 // ------------------------------------------------------------------------------------------------- 203 /*!
199 // 204 * \brief Finds the first instance of a sub-string.
200 int String::find (const char* c, int a) const 205 * \param subString Sub-string to search within this string.
201 { 206 * \param startingPosition Position to start looking for the sub-string from.
202 int pos = m_string.find (c, a); 207 * \returns the position the first instance of sub-string found, or -1 if not found.
203 208 */
204 if (pos == int (std::string::npos)) 209 int String::find (const char* subString, int startingPosition) const
210 {
211 int position = m_string.find (subString, startingPosition);
212
213 if (position == int (std::string::npos))
205 return -1; 214 return -1;
206 215 else
207 return pos; 216 return position;
208 } 217 }
209 218
210 // ------------------------------------------------------------------------------------------------- 219 /*!
211 // 220 * \brief Finds the first instance of a character.
212 int String::find (char ch, int a) const 221 * \param character Character to search within this string.
213 { 222 * \param startingPosition Position to start looking for the character from.
214 int pos = m_string.find (ch, a); 223 * \returns the position of the first instance of the provided character found, or -1 if not found.
215 224 */
216 if (pos == int (std::string::npos)) 225 int String::find (char character, int startingPosition) const
226 {
227 int position = m_string.find (character, startingPosition);
228
229 if (position == int (std::string::npos))
217 return -1; 230 return -1;
218 231 else
219 return pos; 232 return position;
220 } 233 }
221 234
222 // ------------------------------------------------------------------------------------------------- 235 /*!
223 // 236 * \brief Finds the last instance of a sub-string.
224 int String::findLast (const char* c, int a) const 237 * \param subString Sub-string to search within this string.
225 { 238 * \param startingPosition Position to start looking for the sub-string from.
226 if (a == -1 or a >= length()) 239 * \returns the position the last instance of sub-string found, or -1 if not found.
227 a = length() - 1; 240 */
228 241 int String::findLast (const char* subString, int startingPosition) const
229 for (; a > 0; a--) 242 {
230 if (m_string[a] == c[0] and strncmp (chars() + a, c, strlen (c)) == 0) 243 modifyIndex(startingPosition);
231 return a; 244
245 for (; startingPosition > 0; startingPosition--)
246 {
247 if (strncmp (chars() + startingPosition, subString, strlen (subString)) == 0)
248 return startingPosition;
249 }
232 250
233 return -1; 251 return -1;
234 } 252 }
235 253
236 // ------------------------------------------------------------------------------------------------- 254 /*!
237 // 255 * \brief Converts this string to an integer.
256 * \param ok An pointer to a boolean to store whether or not the conversion was successful.
257 * If \c ok is \c NULL, the success state is not stored.
258 * \param base The base to interpret this string with.
259 * \returns the resulting integer.
260 */
238 long String::toInt (bool* ok, int base) const 261 long String::toInt (bool* ok, int base) const
239 { 262 {
240 errno = 0; 263 errno = 0;
241 char* endptr; 264 char* endPointer;
242 long i = strtol (chars(), &endptr, base); 265 long result = strtol (chars(), &endPointer, base);
243 266
244 if (ok) 267 if (ok != nullptr)
245 *ok = (errno == 0 and *endptr == '\0'); 268 *ok = (errno == 0 and *endPointer == '\0');
246 269
247 return i; 270 return result;
248 } 271 }
249 272
250 // ------------------------------------------------------------------------------------------------- 273 /*!
251 // 274 * \brief Converts this string to a floating-point number.
275 * \param ok An pointer to a boolean to store whether or not the conversion was successful.
276 * If \c ok is \c NULL, the success state is not stored.
277 * \returns the resulting floating-point number.
278 */
252 float String::toFloat (bool* ok) const 279 float String::toFloat (bool* ok) const
253 { 280 {
254 errno = 0; 281 return static_cast<float>(toDouble(ok));
255 char* endptr; 282 }
256 float i = (float) strtod (chars(), &endptr); 283
257 284 /*!
258 if (ok != nullptr) 285 * \brief Converts this string to a double-precision floating-point number.
259 *ok = (errno == 0 and *endptr == '\0'); 286 * \param ok An pointer to a boolean to store whether or not the conversion was successful.
260 287 * If \c ok is \c NULL, the success state is not stored.
261 return i; 288 * \returns the resulting floating-point number.
262 } 289 */
263
264 // -------------------------------------------------------------------------------------------------
265 //
266 double String::toDouble (bool* ok) const 290 double String::toDouble (bool* ok) const
267 { 291 {
268 errno = 0; 292 errno = 0;
269 char* endptr; 293 char* endptr;
270 double i = strtod (chars(), &endptr); 294 double i = strtod (chars(), &endptr);
273 *ok = (errno == 0 and *endptr == '\0'); 297 *ok = (errno == 0 and *endptr == '\0');
274 298
275 return i; 299 return i;
276 } 300 }
277 301
278 // ------------------------------------------------------------------------------------------------- 302 /*!
279 // 303 * \brief Catenates this string with another string.
280 String String::operator+ (const String& data) const 304 * \param text String to catenate to the end of this string.
305 * \returns the resulting string.
306 */
307 String String::operator+ (const String& text) const
281 { 308 {
282 String newString = *this; 309 String newString = *this;
283 newString.append (data); 310 newString.append (text);
284 return newString; 311 return newString;
285 } 312 }
286 313
287 // ------------------------------------------------------------------------------------------------- 314 /*!
288 // 315 * \brief Catenates this string with another string.
289 String String::operator+ (const char* data) const 316 * \param text String to catenate to the end of this string.
290 { 317 * \returns the resulting string.
291 String newstr = *this; 318 */
292 newstr.append (data); 319 String String::operator+ (const char* text) const
293 return newstr; 320 {
294 } 321 String newString = *this;
295 322 newString.append (text);
296 // ------------------------------------------------------------------------------------------------- 323 return newString;
297 // 324 }
325
326 /*!
327 * \returns whether or not this string represents a number.
328 */
298 bool String::isNumeric() const 329 bool String::isNumeric() const
299 { 330 {
300 char* endptr; 331 char* endPointer;
301 strtol (chars(), &endptr, 10); 332 strtol (chars(), &endPointer, 10);
302 return not (endptr && *endptr); 333 return (endPointer != nullptr) and (*endPointer != '\0');
303 } 334 }
304 335
305 // ------------------------------------------------------------------------------------------------- 336 /*!
306 // 337 * \param other Sub-string to find from the end of this string.
338 * \return whether or not this string ends with the provided sub-string.
339 */
307 bool String::endsWith (const String& other) const 340 bool String::endsWith (const String& other) const
341 {
342 if (length() < other.length())
343 {
344 return false;
345 }
346 else
347 {
348 const int offset = length() - other.length();
349 return strncmp (chars() + offset, other.chars(), other.length()) == 0;
350 }
351 }
352
353 /*!
354 * \param other Sub-string to find from the beginning of this string.
355 * \returns whether or not this string begins with the provided sub-string.
356 */
357 bool String::startsWith (const String& other) const
308 { 358 {
309 if (length() < other.length()) 359 if (length() < other.length())
310 return false; 360 return false;
311 361 else
312 const int ofs = length() - other.length(); 362 return strncmp (chars(), other.chars(), other.length()) == 0;
313 return strncmp (chars() + ofs, other.chars(), other.length()) == 0; 363 }
314 } 364
315 365 /*!
316 // ------------------------------------------------------------------------------------------------- 366 * \brief Formats this string using \c printf -like syntax.
317 // 367 * \param formatString Template string to use with formatting.
318 bool String::startsWith (const String& other) const 368 * \param ... Variadic arguments to use with formatting.
319 { 369 */
320 if (length() < other.length()) 370 void __cdecl String::sprintf (const char* formatString, ...)
321 return false;
322
323 return strncmp (chars(), other.chars(), other.length()) == 0;
324 }
325
326 // -------------------------------------------------------------------------------------------------
327 //
328 void __cdecl String::sprintf (const char* fmtstr, ...)
329 { 371 {
330 va_list args; 372 va_list args;
331 va_start (args, fmtstr); 373 va_start (args, formatString);
332 this->vsprintf (fmtstr, args); 374 this->vsprintf (formatString, args);
333 va_end (args); 375 va_end (args);
334 } 376 }
335 377
336 // ------------------------------------------------------------------------------------------------- 378 /*!
337 // 379 * \brief Formats this string using \c vsnprintf, using the provided arguments. The buffer string will be repeatedly
338 void String::vsprintf (const char* fmtstr, va_list args) 380 * allocated larger and larger until \c vsnprintf succeeds.
381 * \param formatString Template string to use with formatting.
382 * \param args Variadic arguments to use with formatting.
383 */
384 void String::vsprintf (const char* formatString, va_list args)
339 { 385 {
340 char* buf = nullptr; 386 char* buf = nullptr;
341 int bufsize = 256; 387 int bufsize = 256;
342 388
343 do 389 do
344 { 390 {
345 bufsize *= 2; 391 bufsize *= 2;
346 delete[] buf; 392 delete[] buf;
347 buf = new char[bufsize]; 393 buf = new char[bufsize];
348 } 394 }
349 while (vsnprintf (buf, bufsize, fmtstr, args) >= bufsize); 395 while (vsnprintf (buf, bufsize, formatString, args) >= bufsize);
350 396
351 m_string = buf; 397 m_string = buf;
352 delete[] buf; 398 delete[] buf;
353 } 399 }
354 400
355 // ------------------------------------------------------------------------------------------------- 401 /*!
356 // 402 * \brief Joins the elements of this string list into one longer string.
357 String StringList::join (const String& delim) 403 * \param delimeter The delimeter to place between the element strings.
404 * \returns the catenated string.
405 */
406 String StringList::join (const String& delimeter)
358 { 407 {
359 String result; 408 String result;
360 409
361 for (const String &item : container()) 410 for (const String &item : container())
362 { 411 {
363 if (result.isEmpty() == false) 412 if (result.isEmpty() == false)
364 result += delim; 413 result += delimeter;
365 414
366 result += item; 415 result += item;
367 } 416 }
368 417
369 return result; 418 return result;
370 } 419 }
371 420
372 // ------------------------------------------------------------------------------------------------- 421 /*!
373 // 422 * \brief Tries to match this string against a mask pattern. In the pattern, '?' refers to one character, and '*' to
423 * any number of characters.
424 * \param pattern The masking pattern to use for matching.
425 * \returns whether or not this string matches the provided pattern.
426 */
374 bool String::maskAgainst (const String& pattern) const 427 bool String::maskAgainst (const String& pattern) const
375 { 428 {
376 // Elevate to uppercase for case-insensitive matching 429 // Elevate to uppercase for case-insensitive matching
377 String pattern_upper = pattern.toUpperCase(); 430 String pattern_upper = pattern.toUpperCase();
378 String this_upper = toUpperCase(); 431 String this_upper = toUpperCase();
415 } 468 }
416 469
417 return true; 470 return true;
418 } 471 }
419 472
420 // ------------------------------------------------------------------------------------------------- 473 /*!
421 // 474 * \brief Converts a short integer into a string.
422 String String::fromNumber (short int a) 475 * \param value The value to convert.
423 { 476 * \returns the resulting string.
424 char buf[32]; 477 */
425 ::sprintf (buf, "%d", a); 478 String String::fromNumber (short int value)
426 return String (buf); 479 {
427 } 480 char buffer[32];
428 481 ::sprintf (buffer, "%d", value);
429 // ------------------------------------------------------------------------------------------------- 482 return String (buffer);
430 // 483 }
431 String String::fromNumber (int a) 484
432 { 485 /*!
433 char buf[32]; 486 * \brief Converts an integer into a string.
434 ::sprintf (buf, "%d", a); 487 * \param value The value to convert.
435 return String (buf); 488 * \returns the resulting string.
436 } 489 */
437 490 String String::fromNumber (int value)
438 // ------------------------------------------------------------------------------------------------- 491 {
439 // 492 char buffer[32];
440 String String::fromNumber (long int a) 493 ::sprintf (buffer, "%d", value);
441 { 494 return String (buffer);
442 char buf[32]; 495 }
443 ::sprintf (buf, "%ld", a); 496
444 return String (buf); 497 /*!
445 } 498 * \brief Converts a long integer into a string.
446 499 * \param value The value to convert.
447 // ------------------------------------------------------------------------------------------------- 500 * \returns the resulting string.
448 // 501 */
449 String String::fromNumber (unsigned short int a) 502 String String::fromNumber (long int value)
450 { 503 {
451 char buf[32]; 504 char buffer[32];
452 ::sprintf (buf, "%u", a); 505 ::sprintf (buffer, "%ld", value);
453 return String (buf); 506 return String (buffer);
454 } 507 }
455 508
456 // ------------------------------------------------------------------------------------------------- 509 /*!
457 // 510 * \brief Converts an unsigned short integer into a string.
458 String String::fromNumber (unsigned int a) 511 * \param value The value to convert.
459 { 512 * \returns the resulting string.
460 char buf[32]; 513 */
461 ::sprintf (buf, "%u", a); 514 String String::fromNumber (unsigned short int value)
462 return String (buf); 515 {
463 } 516 char buffer[32];
464 517 ::sprintf (buffer, "%u", value);
465 // ------------------------------------------------------------------------------------------------- 518 return String (buffer);
466 // 519 }
467 String String::fromNumber (unsigned long int a) 520
468 { 521 /*!
469 char buf[32]; 522 * \brief Converts an unsigned integer into a string.
470 ::sprintf (buf, "%lu", a); 523 * \param value The value to convert.
471 return String (buf); 524 * \returns the resulting string.
472 } 525 */
473 526 String String::fromNumber (unsigned int value)
474 // ------------------------------------------------------------------------------------------------- 527 {
475 // 528 char buffer[32];
476 String String::fromNumber (double a) 529 ::sprintf (buffer, "%u", value);
477 { 530 return String (buffer);
478 char buf[64]; 531 }
479 ::sprintf (buf, "%f", a); 532
480 return String (buf); 533 /*!
481 } 534 * \brief Converts an unsigned long integer into a string.
482 535 * \param value The value to convert.
483 // ------------------------------------------------------------------------------------------------- 536 * \returns the resulting string.
484 // 537 */
538 String String::fromNumber (unsigned long int value)
539 {
540 char buffer[32];
541 ::sprintf (buffer, "%lu", value);
542 return String (buffer);
543 }
544
545 /*!
546 * \brief Converts a double-precision floating point number into a string, using the "%f" format specifier.
547 * \param value The value to convert.
548 * \returns the resulting string.
549 */
550 String String::fromNumber (double value)
551 {
552 char buffer[64];
553 ::sprintf (buffer, "%f", value);
554 return String (buffer);
555 }
556
557 /*!
558 * \returns the MD5-checksum of this string.
559 */
485 String String::md5() const 560 String String::md5() const
486 { 561 {
487 char checksum[33]; 562 char checksum[33];
488 CalculateMD5 (reinterpret_cast<const unsigned char*> (chars()), length(), checksum); 563 CalculateMD5 (reinterpret_cast<const unsigned char*> (chars()), length(), checksum);
489 checksum[sizeof checksum - 1] = '\0'; 564 checksum[sizeof checksum - 1] = '\0';
490 return String (checksum); 565 return String (checksum);
491 } 566 }
492 567
493 // ------------------------------------------------------------------------------------------------- 568 /*!
494 // 569 * \brief Removes leading and trailing whitespace from this string. Alternatively a custom filter can be used to strip
570 * something else than whitespace.
571 * \param filter The filtering function to use.
572 */
495 void String::normalize (int (*filter)(int)) 573 void String::normalize (int (*filter)(int))
496 { 574 {
497 int a = 0; 575 int a = 0;
498 int b = length() - 1; 576 int b = length() - 1;
499 577
507 m_string = ""; 585 m_string = "";
508 else if (a != 0 or b != length() - 1) 586 else if (a != 0 or b != length() - 1)
509 m_string = m_string.substr (a, b - a + 1); 587 m_string = m_string.substr (a, b - a + 1);
510 } 588 }
511 589
512 // ------------------------------------------------------------------------------------------------- 590 /*!
513 // 591 * \returns a version of this string without leading or trailing whitespace. Alternatively a custom filter can be used
592 * to strip something else than whitespace.
593 */
514 String String::normalized (int (*filter)(int)) const 594 String String::normalized (int (*filter)(int)) const
515 { 595 {
516 String result = *this; 596 String result = *this;
517 result.normalize(filter); 597 result.normalize(filter);
518 return result; 598 return result;

mercurial