29 */ |
29 */ |
30 |
30 |
31 #include <cstring> |
31 #include <cstring> |
32 #include "main.h" |
32 #include "main.h" |
33 #include "mystring.h" |
33 #include "mystring.h" |
34 #include "md5.h" |
|
35 |
34 |
36 BEGIN_ZFC_NAMESPACE |
35 BEGIN_ZFC_NAMESPACE |
37 |
36 |
38 /*! |
37 /*! |
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 */ |
|
45 int String::compare (const String& other) const |
|
46 { |
|
47 return m_string.compare (other.stdString()); |
|
48 } |
|
49 |
|
50 /*! |
|
51 * \brief Removes all instances of an unwanted character from this string. |
|
52 * \param unwanted Character to remove. |
|
53 */ |
|
54 void String::strip (char unwanted) |
|
55 { |
|
56 for (int pos = 0; (pos = find (unwanted)) != -1;) |
|
57 removeAt (pos--); |
|
58 } |
|
59 |
|
60 /*! |
|
61 * \brief Removes all instances of multiple characters from this string. |
|
62 * \param unwanted Characters to remove. |
|
63 */ |
|
64 void String::strip (const List<char>& unwanted) |
|
65 { |
|
66 for (char character : unwanted) |
|
67 strip(character); |
|
68 } |
|
69 |
|
70 /*! |
|
71 * \returns an upper-case version of this string. |
|
72 */ |
|
73 String String::toUpperCase() const |
|
74 { |
|
75 String result (m_string); |
|
76 |
|
77 for (char &ch : result) |
|
78 { |
|
79 if (islower(ch)) |
|
80 ch -= 'a' - 'A'; |
|
81 } |
|
82 |
|
83 return result; |
|
84 } |
|
85 |
|
86 /*! |
|
87 * \returns a lower-case version of this string. |
38 * \returns a lower-case version of this string. |
88 */ |
39 */ |
89 String String::toLowerCase() const |
40 std::string to_lowercase(const std::string& string) |
90 { |
41 { |
91 String result (m_string); |
42 std::string result = string; |
92 |
43 |
93 for (char &ch : result) |
44 for (char& ch : result) |
94 { |
45 { |
95 if (isupper(ch)) |
46 if (isupper(ch)) |
96 ch += 'a' - 'A'; |
47 ch += 'a' - 'A'; |
97 } |
48 } |
98 |
49 |
99 return result; |
50 return result; |
|
51 } |
|
52 |
|
53 /*! |
|
54 * \brief Joins the elements of this string list into one longer string. |
|
55 * \param delimeter The delimeter to place between the element strings. |
|
56 * \returns the catenated string. |
|
57 */ |
|
58 std::string join_string_list(const std::vector<std::string>& strings, const std::string& delimeter) |
|
59 { |
|
60 std::string result; |
|
61 |
|
62 for (const std::string &item : strings) |
|
63 { |
|
64 if (not result.empty()) |
|
65 result += delimeter; |
|
66 |
|
67 result += item; |
|
68 } |
|
69 |
|
70 return result; |
|
71 } |
|
72 |
|
73 /*! |
|
74 * \brief Modifies the given index so that if it is negative, it is translated into a positive index starting from the |
|
75 * end of the string. For example, an index of -1 will be modified to point to the last character in the string, |
|
76 * -2 to the second last, etc. |
|
77 * \param index Index to translate. |
|
78 */ |
|
79 inline void modifyIndex(const std::string& str, int& index) |
|
80 { |
|
81 if (index < 0) |
|
82 index = str.length() - index; |
|
83 } |
|
84 |
|
85 /*! |
|
86 * \param a Starting index of the range. |
|
87 * \param b Ending index of the range. |
|
88 * \returns a sub-string containing all characters from \c a to \c b, not including the character at \c b. |
|
89 */ |
|
90 std::string mid(const std::string& str, int rangeBegin, int rangeEnd) |
|
91 { |
|
92 modifyIndex(str, rangeBegin); |
|
93 modifyIndex(str, rangeEnd); |
|
94 rangeBegin = max(rangeBegin, 0); |
|
95 rangeEnd = min(rangeEnd, static_cast<signed>(str.length())); |
|
96 |
|
97 if (rangeEnd <= rangeBegin) |
|
98 return ""; |
|
99 else |
|
100 return str.substr(rangeBegin, rangeEnd - rangeBegin); |
|
101 } |
|
102 |
|
103 /*! |
|
104 * \param length Amount of characters to return. |
|
105 * \returns the \c length right-most characters of the string. |
|
106 */ |
|
107 std::string right(const std::string& str, int length) |
|
108 { |
|
109 if (length >= static_cast<signed>(str.length())) |
|
110 return str; |
|
111 else |
|
112 return std::string{str.data() + str.length() - length}; |
|
113 } |
|
114 |
|
115 /*! |
|
116 * \brief Formats this string using \c vsnprintf, using the provided arguments. |
|
117 * \param formatString Template string to use with formatting. |
|
118 * \param args Variadic arguments to use with formatting. |
|
119 */ |
|
120 std::string vsprintf(const char* formatString, va_list args) |
|
121 { |
|
122 std::string result; |
|
123 |
|
124 // Copy the argument list so that we have something to provide to vsnprintf in case we have to call it again. |
|
125 va_list argsCopy; |
|
126 va_copy(argsCopy, args); |
|
127 |
|
128 // First, attempt to format using a fixed-size buffer. |
|
129 static char buffer[1024]; |
|
130 size_t length = vsnprintf(buffer, sizeof buffer, formatString, args); |
|
131 |
|
132 if (length < sizeof buffer) |
|
133 { |
|
134 // vsnprintf succeeded in fitting the formatted string into the buffer, so we're done. |
|
135 result = buffer; |
|
136 } |
|
137 else |
|
138 { |
|
139 // vsnprintf needs more space, so we have to allocate a new buffer and try again. |
|
140 std::vector<char> newBuffer(length + 1); |
|
141 vsnprintf(newBuffer.data(), length + 1, formatString, argsCopy); |
|
142 result = newBuffer.data(); |
|
143 } |
|
144 |
|
145 return result; |
|
146 } |
|
147 |
|
148 /*! |
|
149 * \brief Formats this string using \c printf -like syntax. |
|
150 * \param formatString Template string to use with formatting. |
|
151 * \param ... Variadic arguments to use with formatting. |
|
152 */ |
|
153 std::string __cdecl sprintf(const char* formatString, ...) |
|
154 { |
|
155 va_list args; |
|
156 va_start (args, formatString); |
|
157 std::string result = vsprintf(formatString, args); |
|
158 va_end (args); |
|
159 return result; |
|
160 } |
|
161 |
|
162 std::string remove_range(const std::string &string, int start, int end) |
|
163 { |
|
164 std::string result; |
|
165 result.reserve(string.length() - (end - start)); |
|
166 std::copy(string.begin(), string.begin() + start, std::back_inserter(result)); |
|
167 std::copy(string.begin() + end, string.end(), std::back_inserter(result)); |
|
168 return result; |
|
169 } |
|
170 |
|
171 |
|
172 /*! |
|
173 * \param other Sub-string to find from the beginning of this string. |
|
174 * \returns whether or not this string begins with the provided sub-string. |
|
175 */ |
|
176 bool starts_with(const std::string& str, const std::string& other) |
|
177 { |
|
178 if (str.length() < other.length()) |
|
179 return false; |
|
180 else |
|
181 return std::strncmp(str.data(), other.data(), other.length()) == 0; |
|
182 } |
|
183 |
|
184 /*! |
|
185 * \brief Replaces all instances of \c text with \c replacement. |
|
186 * \param text Text to replace away. |
|
187 * \param replacement Text to replace \c text with. |
|
188 */ |
|
189 void replace_all(std::string& str, const char* text, const char* replacement) |
|
190 { |
|
191 int position; |
|
192 while ((position = str.find(text)) != -1) |
|
193 { |
|
194 str.replace(position, std::strlen(text), replacement); |
|
195 } |
100 } |
196 } |
101 |
197 |
102 /*! |
198 /*! |
103 * \brief Splits this string using the provided delimeter. |
199 * \brief Splits this string using the provided delimeter. |
104 * \param delimeter Delimeter to use for splitting. |
200 * \param delimeter Delimeter to use for splitting. |
105 * \returns a string list containing the split strings. |
201 * \returns a string list containing the split strings. |
106 */ |
202 */ |
107 StringList String::split (char delimeter) const |
203 std::vector<std::string> split(const std::string& string, const std::string& delimeter) |
108 { |
204 { |
109 String delimeterString; |
205 std::vector<std::string> result; |
110 delimeterString += delimeter; |
|
111 return split (delimeterString); |
|
112 } |
|
113 |
|
114 /*! |
|
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; |
|
122 int a = 0; |
206 int a = 0; |
123 int b; |
207 int b; |
124 |
208 |
125 // Find all separators and store the text left to them. |
209 // Find all separators and store the text left to them. |
126 while ((b = find (delimeter, a)) != -1) |
210 while ((b = string.find(delimeter, a)) != -1) |
127 { |
211 { |
128 String sub = mid (a, b); |
212 std::string sub = mid(string, a, b); |
129 |
213 |
130 if (sub.length() > 0) |
214 if (sub.length() > 0) |
131 result << sub; |
215 result.push_back(sub); |
132 |
216 |
133 a = b + delimeter.length(); |
217 a = b + delimeter.length(); |
134 } |
218 } |
135 |
219 |
136 // Add the string at the right of the last separator |
220 // Add the string at the right of the last separator |
137 if (a < (int) length()) |
221 if (a < static_cast<int>(string.length())) |
138 result.append (mid (a, length())); |
222 result.push_back(mid(string, a, string.length())); |
139 |
223 |
140 return result; |
224 return result; |
141 } |
|
142 |
|
143 /*! |
|
144 * \brief Replaces all instances of \c text with \c replacement. |
|
145 * \param text Text to replace away. |
|
146 * \param replacement Text to replace \c text with. |
|
147 */ |
|
148 void String::replace (const char* text, const char* replacement) |
|
149 { |
|
150 int position; |
|
151 |
|
152 while ((position = find (text)) != -1) |
|
153 m_string = m_string.replace (position, strlen (text), replacement); |
|
154 } |
|
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 |
|
161 { |
|
162 int result = 0; |
|
163 |
|
164 for (char ch : *this) |
|
165 { |
|
166 if (ch == character) |
|
167 result++; |
|
168 } |
|
169 |
|
170 return result; |
|
171 } |
|
172 |
|
173 /*! |
|
174 * \param a Starting index of the range. |
|
175 * \param b Ending index of the range. |
|
176 * \returns a sub-string containing all characters from \c a to \c b, not including the character at \c b. |
|
177 */ |
|
178 String String::mid (int rangeBegin, int rangeEnd) const |
|
179 { |
|
180 modifyIndex(rangeBegin); |
|
181 modifyIndex(rangeEnd); |
|
182 rangeBegin = max(rangeBegin, 0); |
|
183 rangeEnd = min(rangeEnd, length()); |
|
184 |
|
185 if (rangeEnd <= rangeBegin) |
|
186 return ""; |
|
187 else |
|
188 return m_string.substr(rangeBegin, rangeEnd - rangeBegin); |
|
189 } |
|
190 |
|
191 /*! |
|
192 * \param length Amount of characters to return. |
|
193 * \returns the \c length right-most characters of the string. |
|
194 */ |
|
195 String String::right(int length) const |
|
196 { |
|
197 if (length >= this->length()) |
|
198 return *this; |
|
199 else |
|
200 return String(chars() + this->length() - length); |
|
201 } |
|
202 |
|
203 /*! |
|
204 * \brief Finds the first instance of a sub-string. |
|
205 * \param subString Sub-string to search within this string. |
|
206 * \param startingPosition Position to start looking for the sub-string from. |
|
207 * \returns the position the first instance of sub-string found, or -1 if not found. |
|
208 */ |
|
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)) |
|
214 return -1; |
|
215 else |
|
216 return position; |
|
217 } |
|
218 |
|
219 /*! |
|
220 * \brief Finds the first instance of a character. |
|
221 * \param character Character to search within this string. |
|
222 * \param startingPosition Position to start looking for the character from. |
|
223 * \returns the position of the first instance of the provided character found, or -1 if not found. |
|
224 */ |
|
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)) |
|
230 return -1; |
|
231 else |
|
232 return position; |
|
233 } |
|
234 |
|
235 /*! |
|
236 * \brief Finds the last instance of a sub-string. |
|
237 * \param subString Sub-string to search within this string. |
|
238 * \param startingPosition Position to start looking for the sub-string from. |
|
239 * \returns the position the last instance of sub-string found, or -1 if not found. |
|
240 */ |
|
241 int String::findLast (const char* subString, int startingPosition) const |
|
242 { |
|
243 modifyIndex(startingPosition); |
|
244 |
|
245 for (; startingPosition > 0; startingPosition--) |
|
246 { |
|
247 if (strncmp (chars() + startingPosition, subString, strlen (subString)) == 0) |
|
248 return startingPosition; |
|
249 } |
|
250 |
|
251 return -1; |
|
252 } |
225 } |
253 |
226 |
254 /*! |
227 /*! |
255 * \brief Converts this string to an integer. |
228 * \brief Converts this string to an integer. |
256 * \param ok An pointer to a boolean to store whether or not the conversion was successful. |
229 * \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. |
230 * If \c ok is \c NULL, the success state is not stored. |
258 * \param base The base to interpret this string with. |
231 * \param base The base to interpret this string with. |
259 * \returns the resulting integer. |
232 * \returns the resulting integer. |
260 */ |
233 */ |
261 long String::toInt (bool* ok, int base) const |
234 std::optional<long> to_int(const char* str, int base) |
262 { |
235 { |
263 errno = 0; |
236 errno = 0; |
264 char* endPointer; |
237 char* endPointer; |
265 long result = strtol (chars(), &endPointer, base); |
238 long result = strtol(str, &endPointer, base); |
266 |
239 if (errno == 0 and *endPointer == '\0') |
267 if (ok != nullptr) |
240 { |
268 *ok = (errno == 0 and *endPointer == '\0'); |
241 return result; |
269 |
242 } |
270 return result; |
243 else |
271 } |
244 { |
272 |
245 return {}; |
273 /*! |
246 } |
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 */ |
|
279 float String::toFloat (bool* ok) const |
|
280 { |
|
281 return static_cast<float>(toDouble(ok)); |
|
282 } |
|
283 |
|
284 /*! |
|
285 * \brief Converts this string to a double-precision floating-point number. |
|
286 * \param ok An pointer to a boolean to store whether or not the conversion was successful. |
|
287 * If \c ok is \c NULL, the success state is not stored. |
|
288 * \returns the resulting floating-point number. |
|
289 */ |
|
290 double String::toDouble (bool* ok) const |
|
291 { |
|
292 errno = 0; |
|
293 char* endptr; |
|
294 double i = strtod (chars(), &endptr); |
|
295 |
|
296 if (ok != nullptr) |
|
297 *ok = (errno == 0 and *endptr == '\0'); |
|
298 |
|
299 return i; |
|
300 } |
|
301 |
|
302 /*! |
|
303 * \brief Catenates this string with another string. |
|
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 |
|
308 { |
|
309 String newString = *this; |
|
310 newString.append (text); |
|
311 return newString; |
|
312 } |
|
313 |
|
314 /*! |
|
315 * \brief Catenates this string with another string. |
|
316 * \param text String to catenate to the end of this string. |
|
317 * \returns the resulting string. |
|
318 */ |
|
319 String String::operator+ (const char* text) const |
|
320 { |
|
321 String newString = *this; |
|
322 newString.append (text); |
|
323 return newString; |
|
324 } |
|
325 |
|
326 /*! |
|
327 * \returns whether or not this string represents a number. |
|
328 */ |
|
329 bool String::isNumeric() const |
|
330 { |
|
331 char* endPointer; |
|
332 strtol (chars(), &endPointer, 10); |
|
333 return (endPointer != nullptr) and (*endPointer != '\0'); |
|
334 } |
|
335 |
|
336 /*! |
|
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 */ |
|
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 |
|
358 { |
|
359 if (length() < other.length()) |
|
360 return false; |
|
361 else |
|
362 return strncmp (chars(), other.chars(), other.length()) == 0; |
|
363 } |
|
364 |
|
365 /*! |
|
366 * \brief Formats this string using \c printf -like syntax. |
|
367 * \param formatString Template string to use with formatting. |
|
368 * \param ... Variadic arguments to use with formatting. |
|
369 */ |
|
370 void __cdecl String::sprintf (const char* formatString, ...) |
|
371 { |
|
372 va_list args; |
|
373 va_start (args, formatString); |
|
374 this->vsprintf (formatString, args); |
|
375 va_end (args); |
|
376 } |
|
377 |
|
378 /*! |
|
379 * \brief Formats this string using \c vsnprintf, using the provided arguments. |
|
380 * \param formatString Template string to use with formatting. |
|
381 * \param args Variadic arguments to use with formatting. |
|
382 */ |
|
383 void String::vsprintf (const char* formatString, va_list args) |
|
384 { |
|
385 // Copy the argument list so that we have something to provide to vsnprintf in case we have to call it again. |
|
386 va_list argsCopy; |
|
387 va_copy(argsCopy, args); |
|
388 |
|
389 // First, attempt to format using a fixed-size buffer. |
|
390 static char buffer[1024]; |
|
391 size_t length = vsnprintf(buffer, sizeof buffer, formatString, args); |
|
392 |
|
393 if (length < sizeof buffer) |
|
394 { |
|
395 // vsnprintf succeeded in fitting the formatted string into the buffer, so we're done. |
|
396 m_string = buffer; |
|
397 } |
|
398 else |
|
399 { |
|
400 // vsnprintf needs more space, so we have to allocate a new buffer and try again. |
|
401 Vector<char> newBuffer(length + 1); |
|
402 vsnprintf(newBuffer.data(), length + 1, formatString, argsCopy); |
|
403 m_string = newBuffer; |
|
404 } |
|
405 } |
|
406 |
|
407 /*! |
|
408 * \brief Joins the elements of this string list into one longer string. |
|
409 * \param delimeter The delimeter to place between the element strings. |
|
410 * \returns the catenated string. |
|
411 */ |
|
412 String StringList::join (const String& delimeter) |
|
413 { |
|
414 String result; |
|
415 |
|
416 for (const String &item : container()) |
|
417 { |
|
418 if (result.isEmpty() == false) |
|
419 result += delimeter; |
|
420 |
|
421 result += item; |
|
422 } |
|
423 |
|
424 return result; |
|
425 } |
|
426 |
|
427 /*! |
|
428 * \brief Tries to match this string against a mask pattern. In the pattern, '?' refers to one character, and '*' to |
|
429 * any number of characters. |
|
430 * \param pattern The masking pattern to use for matching. |
|
431 * \returns whether or not this string matches the provided pattern. |
|
432 */ |
|
433 bool String::maskAgainst (const String& pattern) const |
|
434 { |
|
435 // Elevate to uppercase for case-insensitive matching |
|
436 String pattern_upper = pattern.toUpperCase(); |
|
437 String this_upper = toUpperCase(); |
|
438 const char* maskstring = pattern_upper.chars(); |
|
439 const char* mptr = &maskstring[0]; |
|
440 |
|
441 for (const char* sptr = this_upper.chars(); *sptr != '\0'; sptr++) |
|
442 { |
|
443 if (*mptr == '?') |
|
444 { |
|
445 if (*(sptr + 1) == '\0') |
|
446 { |
|
447 // ? demands that there's a character here and there wasn't. |
|
448 // Therefore, mask matching fails |
|
449 return false; |
|
450 } |
|
451 } |
|
452 else if (*mptr == '*') |
|
453 { |
|
454 char end = *(++mptr); |
|
455 |
|
456 // If '*' is the final character of the message, all of the remaining |
|
457 // string matches against the '*'. We don't need to bother checking |
|
458 // the string any further. |
|
459 if (end == '\0') |
|
460 return true; |
|
461 |
|
462 // Skip to the end character |
|
463 while (*sptr != end and *sptr != '\0') |
|
464 sptr++; |
|
465 |
|
466 // String ended while the mask still had stuff |
|
467 if (*sptr == '\0') |
|
468 return false; |
|
469 } |
|
470 else if (*sptr != *mptr) |
|
471 return false; |
|
472 |
|
473 mptr++; |
|
474 } |
|
475 |
|
476 return true; |
|
477 } |
|
478 |
|
479 /*! |
|
480 * \brief Converts a short integer into a string. |
|
481 * \param value The value to convert. |
|
482 * \returns the resulting string. |
|
483 */ |
|
484 String String::fromNumber (short int value) |
|
485 { |
|
486 char buffer[32]; |
|
487 ::sprintf (buffer, "%d", value); |
|
488 return String (buffer); |
|
489 } |
|
490 |
|
491 /*! |
|
492 * \brief Converts an integer into a string. |
|
493 * \param value The value to convert. |
|
494 * \returns the resulting string. |
|
495 */ |
|
496 String String::fromNumber (int value) |
|
497 { |
|
498 char buffer[32]; |
|
499 ::sprintf (buffer, "%d", value); |
|
500 return String (buffer); |
|
501 } |
|
502 |
|
503 /*! |
|
504 * \brief Converts a long integer into a string. |
|
505 * \param value The value to convert. |
|
506 * \returns the resulting string. |
|
507 */ |
|
508 String String::fromNumber (long int value) |
|
509 { |
|
510 char buffer[32]; |
|
511 ::sprintf (buffer, "%ld", value); |
|
512 return String (buffer); |
|
513 } |
|
514 |
|
515 /*! |
|
516 * \brief Converts an unsigned short integer into a string. |
|
517 * \param value The value to convert. |
|
518 * \returns the resulting string. |
|
519 */ |
|
520 String String::fromNumber (unsigned short int value) |
|
521 { |
|
522 char buffer[32]; |
|
523 ::sprintf (buffer, "%u", value); |
|
524 return String (buffer); |
|
525 } |
|
526 |
|
527 /*! |
|
528 * \brief Converts an unsigned integer into a string. |
|
529 * \param value The value to convert. |
|
530 * \returns the resulting string. |
|
531 */ |
|
532 String String::fromNumber (unsigned int value) |
|
533 { |
|
534 char buffer[32]; |
|
535 ::sprintf (buffer, "%u", value); |
|
536 return String (buffer); |
|
537 } |
|
538 |
|
539 /*! |
|
540 * \brief Converts an unsigned long integer into a string. |
|
541 * \param value The value to convert. |
|
542 * \returns the resulting string. |
|
543 */ |
|
544 String String::fromNumber (unsigned long int value) |
|
545 { |
|
546 char buffer[32]; |
|
547 ::sprintf (buffer, "%lu", value); |
|
548 return String (buffer); |
|
549 } |
|
550 |
|
551 /*! |
|
552 * \brief Converts a double-precision floating point number into a string, using the "%f" format specifier. |
|
553 * \param value The value to convert. |
|
554 * \returns the resulting string. |
|
555 */ |
|
556 String String::fromNumber (double value) |
|
557 { |
|
558 char buffer[64]; |
|
559 ::sprintf (buffer, "%f", value); |
|
560 return String (buffer); |
|
561 } |
|
562 |
|
563 /*! |
|
564 * \brief Constructs a string from a vector of bytes. The bytes do not have to be null-terminated. |
|
565 * \param bytes Bytes to use for construction |
|
566 * \returns the resulting string. |
|
567 */ |
|
568 String String::fromBytes(const ByteArray& bytes) |
|
569 { |
|
570 return String(reinterpret_cast<const Vector<char>&>(bytes)); |
|
571 } |
|
572 |
|
573 /*! |
|
574 * \returns the MD5-checksum of this string. |
|
575 */ |
|
576 String String::md5() const |
|
577 { |
|
578 char checksum[33]; |
|
579 CalculateMD5 (reinterpret_cast<const unsigned char*> (chars()), length(), checksum); |
|
580 checksum[sizeof checksum - 1] = '\0'; |
|
581 return String (checksum); |
|
582 } |
247 } |
583 |
248 |
584 /*! |
249 /*! |
585 * \brief Removes leading and trailing whitespace from this string. Alternatively a custom filter can be used to strip |
250 * \brief Removes leading and trailing whitespace from this string. Alternatively a custom filter can be used to strip |
586 * something else than whitespace. |
251 * something else than whitespace. |
587 * \param filter The filtering function to use. |
252 * \param filter The filtering function to use. |
588 */ |
253 */ |
589 void String::normalize (int (*filter)(int)) |
254 void normalize(std::string& string, int (*filter)(int)) |
590 { |
255 { |
591 int a = 0; |
256 int a = 0; |
592 int b = length() - 1; |
257 int b = string.length() - 1; |
593 |
258 while ((*filter)(string[a]) and a != b) |
594 while ((*filter) (m_string[a]) and a != b) |
259 { |
595 ++a; |
260 ++a; |
596 |
261 } |
597 while ((*filter) (m_string[b]) and a != b) |
262 while ((*filter)(string[b]) and a != b) |
|
263 { |
598 --b; |
264 --b; |
599 |
265 } |
600 if (a == b) |
266 if (a == b) |
601 m_string = ""; |
267 { |
602 else if (a != 0 or b != length() - 1) |
268 string = ""; |
603 m_string = m_string.substr (a, b - a + 1); |
269 } |
604 } |
270 else if (a != 0 or b != static_cast<signed>(string.length() - 1)) |
605 |
271 { |
606 /*! |
272 string = string.substr (a, b - a + 1); |
607 * \returns a version of this string without leading or trailing whitespace. Alternatively a custom filter can be used |
273 } |
608 * to strip something else than whitespace. |
|
609 */ |
|
610 String String::normalized (int (*filter)(int)) const |
|
611 { |
|
612 String result = *this; |
|
613 result.normalize(filter); |
|
614 return result; |
|
615 } |
274 } |
616 |
275 |
617 END_ZFC_NAMESPACE |
276 END_ZFC_NAMESPACE |