/src/poco/Foundation/include/Poco/String.h
Line | Count | Source (jump to first uncovered line) |
1 | | // |
2 | | // String.h |
3 | | // |
4 | | // Library: Foundation |
5 | | // Package: Core |
6 | | // Module: String |
7 | | // |
8 | | // String utility functions. |
9 | | // |
10 | | // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. |
11 | | // and Contributors. |
12 | | // |
13 | | // SPDX-License-Identifier: BSL-1.0 |
14 | | // |
15 | | |
16 | | |
17 | | #ifndef Foundation_String_INCLUDED |
18 | | #define Foundation_String_INCLUDED |
19 | | |
20 | | |
21 | | #include "Poco/Foundation.h" |
22 | | #include "Poco/Ascii.h" |
23 | | #include <cstring> |
24 | | #if !defined(POCO_NO_WSTRING) |
25 | | #include <cwchar> |
26 | | #endif |
27 | | #include <algorithm> |
28 | | |
29 | | |
30 | | // ignore loop unrolling warnings in this file |
31 | | #if defined(__clang__) && ((__clang_major__ > 3) || (__clang_major__ == 3 && __clang_minor__ >= 6)) |
32 | | # pragma clang diagnostic push |
33 | | # pragma clang diagnostic ignored "-Wpass-failed" |
34 | | #endif |
35 | | |
36 | | |
37 | | namespace Poco { |
38 | | |
39 | | |
40 | | template <typename C> |
41 | | std::size_t cstrlen(const C* str) |
42 | | /// Returns the length of a zero-terminated C string. |
43 | | /// For char and wchar_t based strings, overloads are |
44 | | /// provided that call strlen() and wcslen(). |
45 | | { |
46 | | const C* end = str; |
47 | | while (*end) ++end; |
48 | | return end - str; |
49 | | } |
50 | | |
51 | | |
52 | | inline std::size_t cstrlen(const char* str) |
53 | | /// Returns the length of a zero-terminated C string. |
54 | | /// This implementation calls std::strlen(). |
55 | 0 | { |
56 | 0 | return std::strlen(str); |
57 | 0 | } |
58 | | |
59 | | |
60 | | #if !defined(POCO_NO_WSTRING) |
61 | | |
62 | | |
63 | | inline std::size_t cstrlen(const wchar_t* str) |
64 | | /// Returns the length of a zero-terminated C string. |
65 | | /// This implementation calls std::wcslen(). |
66 | 0 | { |
67 | 0 | return std::wcslen(str); |
68 | 0 | } |
69 | | |
70 | | |
71 | | #endif |
72 | | |
73 | | |
74 | | template <class S> |
75 | | S trimLeft(const S& str) |
76 | | /// Returns a copy of str with all leading |
77 | | /// whitespace removed. |
78 | | { |
79 | | typename S::const_iterator it = str.begin(); |
80 | | typename S::const_iterator end = str.end(); |
81 | | |
82 | | while (it != end && Ascii::isSpace(*it)) ++it; |
83 | | return S(it, end); |
84 | | } |
85 | | |
86 | | |
87 | | template <class S> |
88 | | S& trimLeftInPlace(S& str) |
89 | | /// Removes all leading whitespace in str. |
90 | | { |
91 | | typename S::iterator it = str.begin(); |
92 | | typename S::iterator end = str.end(); |
93 | | |
94 | | while (it != end && Ascii::isSpace(*it)) ++it; |
95 | | str.erase(str.begin(), it); |
96 | | return str; |
97 | | } |
98 | | |
99 | | |
100 | | template <class S> |
101 | | S trimRight(const S& str) |
102 | | /// Returns a copy of str with all trailing |
103 | | /// whitespace removed. |
104 | | { |
105 | | std::ptrdiff_t pos = static_cast<std::ptrdiff_t>(str.size()) - 1; |
106 | | |
107 | | while (pos >= 0 && Ascii::isSpace(str[pos])) --pos; |
108 | | return S(str, 0, pos + 1); |
109 | | } |
110 | | |
111 | | |
112 | | template <class S> |
113 | | S& trimRightInPlace(S& str) |
114 | | /// Removes all trailing whitespace in str. |
115 | 721k | { |
116 | 721k | std::ptrdiff_t pos = static_cast<std::ptrdiff_t>(str.size()) - 1; |
117 | | |
118 | 815k | while (pos >= 0 && Ascii::isSpace(str[pos])) --pos; |
119 | 721k | str.resize(pos + 1); |
120 | | |
121 | 721k | return str; |
122 | 721k | } |
123 | | |
124 | | |
125 | | template <class S> |
126 | | S trim(const S& str) |
127 | | /// Returns a copy of str with all leading and |
128 | | /// trailing whitespace removed. |
129 | 0 | { |
130 | 0 | std::ptrdiff_t first = 0; |
131 | 0 | std::ptrdiff_t last = static_cast<std::ptrdiff_t>(str.size()) - 1; |
132 | |
|
133 | 0 | while (first <= last && Ascii::isSpace(str[first])) ++first; |
134 | 0 | while (last >= first && Ascii::isSpace(str[last])) --last; |
135 | |
|
136 | 0 | return S(str, first, last - first + 1); |
137 | 0 | } |
138 | | |
139 | | |
140 | | template <class S> |
141 | | S& trimInPlace(S& str) |
142 | | /// Removes all leading and trailing whitespace in str. |
143 | 0 | { |
144 | 0 | std::ptrdiff_t first = 0; |
145 | 0 | std::ptrdiff_t last = static_cast<std::ptrdiff_t>(str.size()) - 1; |
146 | |
|
147 | 0 | while (first <= last && Ascii::isSpace(str[first])) ++first; |
148 | 0 | while (last >= first && Ascii::isSpace(str[last])) --last; |
149 | |
|
150 | 0 | if (last >= 0) |
151 | 0 | { |
152 | 0 | str.resize(last + 1); |
153 | 0 | str.erase(0, first); |
154 | 0 | } |
155 | 0 | return str; |
156 | 0 | } |
157 | | |
158 | | |
159 | | template <class S> |
160 | | S toUpper(const S& str) |
161 | | /// Returns a copy of str containing all upper-case characters. |
162 | 63.2k | { |
163 | 63.2k | S result(str); |
164 | | |
165 | 63.2k | typename S::iterator it = result.begin(); |
166 | 63.2k | typename S::iterator end = result.end(); |
167 | | |
168 | 63.2k | #if defined(__clang__) && ((__clang_major__ > 3) || (__clang_major__ == 3 && __clang_minor__ >= 6)) |
169 | 63.2k | # pragma clang loop unroll(enable) |
170 | | #elif defined(POCO_MSVS_VERSION) && (POCO_MSVS_VERSION >= 2017) |
171 | | # pragma loop(hint_parallel(0)) |
172 | | #endif |
173 | 337k | while (it != end) |
174 | 274k | { |
175 | 274k | int ch = static_cast<unsigned char>(*it); |
176 | 274k | *it = static_cast<typename S::value_type>(Ascii::toUpper(ch)); |
177 | 274k | ++it; |
178 | 274k | } |
179 | 63.2k | return result; |
180 | 63.2k | } |
181 | | |
182 | | |
183 | | template <class S> |
184 | | S& toUpperInPlace(S& str) |
185 | | /// Replaces all characters in str with their upper-case counterparts. |
186 | | { |
187 | | typename S::iterator it = str.begin(); |
188 | | typename S::iterator end = str.end(); |
189 | | |
190 | | #if defined(__clang__) && ((__clang_major__ > 3) || (__clang_major__ == 3 && __clang_minor__ >= 6)) |
191 | | # pragma clang loop unroll(enable) |
192 | | #elif defined(POCO_MSVS_VERSION) && (POCO_MSVS_VERSION >= 2017) |
193 | | # pragma loop(hint_parallel(0)) |
194 | | #endif |
195 | | while (it != end) |
196 | | { |
197 | | int ch = static_cast<unsigned char>(*it); |
198 | | *it = static_cast<typename S::value_type>(Ascii::toUpper(ch)); |
199 | | ++it; |
200 | | } |
201 | | return str; |
202 | | } |
203 | | |
204 | | |
205 | | template <class S> |
206 | | S toLower(const S& str) |
207 | | /// Returns a copy of str containing all lower-case characters. |
208 | 47.6k | { |
209 | 47.6k | S result(str); |
210 | | |
211 | 47.6k | typename S::iterator it = result.begin(); |
212 | 47.6k | typename S::iterator end = result.end(); |
213 | | |
214 | 47.6k | #if defined(__clang__) && ((__clang_major__ > 3) || (__clang_major__ == 3 && __clang_minor__ >= 6)) |
215 | 47.6k | # pragma clang loop unroll(enable) |
216 | | #elif defined(POCO_MSVS_VERSION) && (POCO_MSVS_VERSION >= 2017) |
217 | | # pragma loop(hint_parallel(0)) |
218 | | #endif |
219 | 764k | while (it != end) |
220 | 716k | { |
221 | 716k | int ch = static_cast<unsigned char>(*it); |
222 | 716k | *it = static_cast<typename S::value_type>(Ascii::toLower(ch)); |
223 | 716k | ++it; |
224 | 716k | } |
225 | 47.6k | return result; |
226 | 47.6k | } |
227 | | |
228 | | |
229 | | template <class S> |
230 | | S& toLowerInPlace(S& str) |
231 | | /// Replaces all characters in str with their lower-case counterparts. |
232 | 60.6k | { |
233 | 60.6k | typename S::iterator it = str.begin(); |
234 | 60.6k | typename S::iterator end = str.end(); |
235 | | |
236 | 60.6k | #if defined(__clang__) && ((__clang_major__ > 3) || (__clang_major__ == 3 && __clang_minor__ >= 6)) |
237 | 60.6k | # pragma clang loop unroll(enable) |
238 | | #elif defined(POCO_MSVS_VERSION) && (POCO_MSVS_VERSION >= 2017) |
239 | | # pragma loop(hint_parallel(0)) |
240 | | #endif |
241 | 108M | while (it != end) |
242 | 108M | { |
243 | 108M | int ch = static_cast<unsigned char>(*it); |
244 | 108M | *it = static_cast<typename S::value_type>(Ascii::toLower(ch)); |
245 | 108M | ++it; |
246 | 108M | } |
247 | 60.6k | return str; |
248 | 60.6k | } |
249 | | |
250 | | |
251 | | #if !defined(POCO_NO_TEMPLATE_ICOMPARE) |
252 | | |
253 | | |
254 | | template <class S, class It> |
255 | | int icompare( |
256 | | const S& str, |
257 | | typename S::size_type pos, |
258 | | typename S::size_type n, |
259 | | It it2, |
260 | | It end2) |
261 | | /// Case-insensitive string comparison |
262 | | { |
263 | | typename S::size_type sz = str.size(); |
264 | | if (pos > sz) pos = sz; |
265 | | if (pos + n > sz) n = sz - pos; |
266 | | It it1 = str.begin() + pos; |
267 | | It end1 = str.begin() + pos + n; |
268 | | while (it1 != end1 && it2 != end2) |
269 | | { |
270 | | typename S::value_type c1(static_cast<typename S::value_type>(Ascii::toLower(*it1))); |
271 | | typename S::value_type c2(static_cast<typename S::value_type>(Ascii::toLower(*it2))); |
272 | | if (c1 < c2) |
273 | | return -1; |
274 | | else if (c1 > c2) |
275 | | return 1; |
276 | | ++it1; ++it2; |
277 | | } |
278 | | |
279 | | if (it1 == end1) |
280 | | return it2 == end2 ? 0 : -1; |
281 | | else |
282 | | return 1; |
283 | | } |
284 | | |
285 | | |
286 | | template <class S> |
287 | | int icompare(const S& str1, const S& str2) |
288 | | // A special optimization for an often used case. |
289 | 55.1M | { |
290 | 55.1M | typename S::const_iterator it1(str1.begin()); |
291 | 55.1M | const typename S::const_iterator end1(str1.end()); |
292 | 55.1M | typename S::const_iterator it2(str2.begin()); |
293 | 55.1M | const typename S::const_iterator end2(str2.end()); |
294 | 122M | while (it1 != end1 && it2 != end2) |
295 | 71.2M | { |
296 | 71.2M | const typename S::value_type c1(static_cast<typename S::value_type>(Ascii::toLower(*it1))); |
297 | 71.2M | const typename S::value_type c2(static_cast<typename S::value_type>(Ascii::toLower(*it2))); |
298 | 71.2M | if (c1 < c2) |
299 | 942k | return -1; |
300 | 70.2M | else if (c1 > c2) |
301 | 2.48M | return 1; |
302 | 67.7M | ++it1; ++it2; |
303 | 67.7M | } |
304 | | |
305 | 51.7M | if (it1 == end1) |
306 | 51.6M | return it2 == end2 ? 0 : -1; |
307 | 69.2k | else |
308 | 69.2k | return 1; |
309 | 51.7M | } |
310 | | |
311 | | |
312 | | template <class S> |
313 | | int icompare(const S& str1, typename S::size_type n1, const S& str2, typename S::size_type n2) |
314 | | { |
315 | | if (n2 > str2.size()) n2 = str2.size(); |
316 | | return icompare(str1, 0, n1, str2.begin(), str2.begin() + n2); |
317 | | } |
318 | | |
319 | | |
320 | | template <class S> |
321 | | int icompare(const S& str1, typename S::size_type n, const S& str2) |
322 | | { |
323 | | if (n > str2.size()) n = str2.size(); |
324 | | return icompare(str1, 0, n, str2.begin(), str2.begin() + n); |
325 | | } |
326 | | |
327 | | |
328 | | template <class S> |
329 | | int icompare(const S& str1, typename S::size_type pos, typename S::size_type n, const S& str2) |
330 | | { |
331 | | return icompare(str1, pos, n, str2.begin(), str2.end()); |
332 | | } |
333 | | |
334 | | |
335 | | template <class S> |
336 | | int icompare( |
337 | | const S& str1, |
338 | | typename S::size_type pos1, |
339 | | typename S::size_type n1, |
340 | | const S& str2, |
341 | | typename S::size_type pos2, |
342 | | typename S::size_type n2) |
343 | | { |
344 | | typename S::size_type sz2 = str2.size(); |
345 | | if (pos2 > sz2) pos2 = sz2; |
346 | | if (pos2 + n2 > sz2) n2 = sz2 - pos2; |
347 | | return icompare(str1, pos1, n1, str2.begin() + pos2, str2.begin() + pos2 + n2); |
348 | | } |
349 | | |
350 | | |
351 | | template <class S> |
352 | | int icompare( |
353 | | const S& str1, |
354 | | typename S::size_type pos1, |
355 | | typename S::size_type n, |
356 | | const S& str2, |
357 | | typename S::size_type pos2) |
358 | | { |
359 | | typename S::size_type sz2 = str2.size(); |
360 | | if (pos2 > sz2) pos2 = sz2; |
361 | | if (pos2 + n > sz2) n = sz2 - pos2; |
362 | | return icompare(str1, pos1, n, str2.begin() + pos2, str2.begin() + pos2 + n); |
363 | | } |
364 | | |
365 | | |
366 | | template <class S> |
367 | | int icompare( |
368 | | const S& str, |
369 | | typename S::size_type pos, |
370 | | typename S::size_type n, |
371 | | const typename S::value_type* ptr) |
372 | 367k | { |
373 | 367k | poco_check_ptr (ptr); |
374 | 367k | typename S::size_type sz = str.size(); |
375 | 367k | if (pos > sz) pos = sz; |
376 | 367k | if (pos + n > sz) n = sz - pos; |
377 | 367k | typename S::const_iterator it = str.begin() + pos; |
378 | 367k | typename S::const_iterator end = str.begin() + pos + n; |
379 | 466k | while (it != end && *ptr) |
380 | 454k | { |
381 | 454k | typename S::value_type c1(static_cast<typename S::value_type>(Ascii::toLower(*it))); |
382 | 454k | typename S::value_type c2(static_cast<typename S::value_type>(Ascii::toLower(*ptr))); |
383 | 454k | if (c1 < c2) |
384 | 211k | return -1; |
385 | 243k | else if (c1 > c2) |
386 | 144k | return 1; |
387 | 98.4k | ++it; ++ptr; |
388 | 98.4k | } |
389 | | |
390 | 11.3k | if (it == end) |
391 | 11.0k | return *ptr == 0 ? 0 : -1; |
392 | 281 | else |
393 | 281 | return 1; |
394 | 11.3k | } |
395 | | |
396 | | |
397 | | template <class S> |
398 | | int icompare( |
399 | | const S& str, |
400 | | typename S::size_type pos, |
401 | | const typename S::value_type* ptr) |
402 | | { |
403 | | int n = static_cast<int>(pos < str.size() ? str.size() - pos : 0); |
404 | | return icompare(str, pos, n, ptr); |
405 | | } |
406 | | |
407 | | |
408 | | template <class S> |
409 | | int icompare( |
410 | | const S& str, |
411 | | const typename S::value_type* ptr) |
412 | 367k | { |
413 | 367k | return icompare(str, 0, str.size(), ptr); |
414 | 367k | } |
415 | | |
416 | | |
417 | | #else |
418 | | |
419 | | |
420 | | int Foundation_API icompare(const std::string& str, std::string::size_type pos, std::string::size_type n, std::string::const_iterator it2, std::string::const_iterator end2); |
421 | | int Foundation_API icompare(const std::string& str1, const std::string& str2); |
422 | | int Foundation_API icompare(const std::string& str1, std::string::size_type n1, const std::string& str2, std::string::size_type n2); |
423 | | int Foundation_API icompare(const std::string& str1, std::string::size_type n, const std::string& str2); |
424 | | int Foundation_API icompare(const std::string& str1, std::string::size_type pos, std::string::size_type n, const std::string& str2); |
425 | | int Foundation_API icompare(const std::string& str1, std::string::size_type pos1, std::string::size_type n1, const std::string& str2, std::string::size_type pos2, std::string::size_type n2); |
426 | | int Foundation_API icompare(const std::string& str1, std::string::size_type pos1, std::string::size_type n, const std::string& str2, std::string::size_type pos2); |
427 | | int Foundation_API icompare(const std::string& str, std::string::size_type pos, std::string::size_type n, const std::string::value_type* ptr); |
428 | | int Foundation_API icompare(const std::string& str, std::string::size_type pos, const std::string::value_type* ptr); |
429 | | int Foundation_API icompare(const std::string& str, const std::string::value_type* ptr); |
430 | | |
431 | | |
432 | | #endif |
433 | | |
434 | | |
435 | | template <class S> |
436 | | S translate(const S& str, const S& from, const S& to) |
437 | | /// Returns a copy of str with all characters in |
438 | | /// from replaced by the corresponding (by position) |
439 | | /// characters in to. If there is no corresponding |
440 | | /// character in to, the character is removed from |
441 | | /// the copy. |
442 | 0 | { |
443 | 0 | S result; |
444 | 0 | result.reserve(str.size()); |
445 | 0 | typename S::const_iterator it = str.begin(); |
446 | 0 | typename S::const_iterator end = str.end(); |
447 | 0 | typename S::size_type toSize = to.size(); |
448 | 0 | while (it != end) |
449 | 0 | { |
450 | 0 | typename S::size_type pos = from.find(*it); |
451 | 0 | if (pos == S::npos) |
452 | 0 | { |
453 | 0 | result += *it; |
454 | 0 | } |
455 | 0 | else |
456 | 0 | { |
457 | 0 | if (pos < toSize) result += to[pos]; |
458 | 0 | } |
459 | 0 | ++it; |
460 | 0 | } |
461 | 0 | return result; |
462 | 0 | } |
463 | | |
464 | | |
465 | | template <class S> |
466 | | S translate(const S& str, const typename S::value_type* from, const typename S::value_type* to) |
467 | 0 | { |
468 | 0 | poco_check_ptr (from); |
469 | 0 | poco_check_ptr (to); |
470 | 0 | return translate(str, S(from), S(to)); |
471 | 0 | } |
472 | | |
473 | | |
474 | | template <class S> |
475 | | S& translateInPlace(S& str, const S& from, const S& to) |
476 | | /// Replaces in str all occurrences of characters in from |
477 | | /// with the corresponding (by position) characters in to. |
478 | | /// If there is no corresponding character, the character |
479 | | /// is removed. |
480 | | { |
481 | | str = translate(str, from, to); |
482 | | return str; |
483 | | } |
484 | | |
485 | | |
486 | | template <class S> |
487 | | S translateInPlace(S& str, const typename S::value_type* from, const typename S::value_type* to) |
488 | | { |
489 | | poco_check_ptr (from); |
490 | | poco_check_ptr (to); |
491 | | str = translate(str, S(from), S(to)); |
492 | | #if defined(__SUNPRO_CC) |
493 | | // Fix around the RVO bug in SunStudio 12.4 |
494 | | S ret(str); |
495 | | return ret; |
496 | | #else |
497 | | return str; |
498 | | #endif |
499 | | } |
500 | | |
501 | | |
502 | | #if !defined(POCO_NO_TEMPLATE_ICOMPARE) |
503 | | |
504 | | |
505 | | template <class S> |
506 | | S& replaceInPlace(S& str, const S& from, const S& to, typename S::size_type start = 0) |
507 | | { |
508 | | poco_assert (from.size() > 0); |
509 | | |
510 | | S result; |
511 | | typename S::size_type pos = 0; |
512 | | result.append(str, 0, start); |
513 | | do |
514 | | { |
515 | | pos = str.find(from, start); |
516 | | if (pos != S::npos) |
517 | | { |
518 | | result.append(str, start, pos - start); |
519 | | result.append(to); |
520 | | start = pos + from.length(); |
521 | | } |
522 | | else result.append(str, start, str.size() - start); |
523 | | } |
524 | | while (pos != S::npos); |
525 | | str.swap(result); |
526 | | return str; |
527 | | } |
528 | | |
529 | | |
530 | | template <class S> |
531 | | S& replaceInPlace(S& str, const typename S::value_type* from, const typename S::value_type* to, typename S::size_type start = 0) |
532 | 0 | { |
533 | 0 | poco_assert (*from); |
534 | |
|
535 | 0 | S result; |
536 | 0 | typename S::size_type pos = 0; |
537 | 0 | typename S::size_type fromLen = cstrlen(from); |
538 | 0 | result.append(str, 0, start); |
539 | 0 | do |
540 | 0 | { |
541 | 0 | pos = str.find(from, start); |
542 | 0 | if (pos != S::npos) |
543 | 0 | { |
544 | 0 | result.append(str, start, pos - start); |
545 | 0 | result.append(to); |
546 | 0 | start = pos + fromLen; |
547 | 0 | } |
548 | 0 | else result.append(str, start, str.size() - start); |
549 | 0 | } |
550 | 0 | while (pos != S::npos); |
551 | 0 | str.swap(result); |
552 | 0 | return str; |
553 | 0 | } |
554 | | |
555 | | |
556 | | template <class S> |
557 | | S& replaceInPlace(S& str, const typename S::value_type from, const typename S::value_type to = 0, typename S::size_type start = 0) |
558 | 0 | { |
559 | 0 | if (from == to) return str; |
560 | | |
561 | 0 | typename S::size_type pos = 0; |
562 | 0 | do |
563 | 0 | { |
564 | 0 | pos = str.find(from, start); |
565 | 0 | if (pos != S::npos) |
566 | 0 | { |
567 | 0 | if (to) str[pos] = to; |
568 | 0 | else str.erase(pos, 1); |
569 | 0 | } |
570 | 0 | } while (pos != S::npos); |
571 | |
|
572 | 0 | return str; |
573 | 0 | } |
574 | | |
575 | | |
576 | | template <class S> |
577 | | S& removeInPlace(S& str, const typename S::value_type ch, typename S::size_type start = 0) |
578 | 0 | { |
579 | 0 | return replaceInPlace(str, ch, 0, start); |
580 | 0 | } |
581 | | |
582 | | |
583 | | template <class S> |
584 | | S replace(const S& str, const S& from, const S& to, typename S::size_type start = 0) |
585 | | /// Replace all occurrences of from (which must not be the empty string) |
586 | | /// in str with to, starting at position start. |
587 | | { |
588 | | S result(str); |
589 | | replaceInPlace(result, from, to, start); |
590 | | return result; |
591 | | } |
592 | | |
593 | | |
594 | | template <class S> |
595 | | S replace(const S& str, const typename S::value_type* from, const typename S::value_type* to, typename S::size_type start = 0) |
596 | | { |
597 | | S result(str); |
598 | | replaceInPlace(result, from, to, start); |
599 | | return result; |
600 | | } |
601 | | |
602 | | |
603 | | template <class S> |
604 | | S replace(const S& str, const typename S::value_type from, const typename S::value_type to = 0, typename S::size_type start = 0) |
605 | | { |
606 | | S result(str); |
607 | | replaceInPlace(result, from, to, start); |
608 | | return result; |
609 | | } |
610 | | |
611 | | |
612 | | template <class S> |
613 | | S remove(const S& str, const typename S::value_type ch, typename S::size_type start = 0) |
614 | | { |
615 | | S result(str); |
616 | | replaceInPlace(result, ch, 0, start); |
617 | | return result; |
618 | | } |
619 | | |
620 | | |
621 | | #else |
622 | | |
623 | | |
624 | | Foundation_API std::string replace(const std::string& str, const std::string& from, const std::string& to, std::string::size_type start = 0); |
625 | | Foundation_API std::string replace(const std::string& str, const std::string::value_type* from, const std::string::value_type* to, std::string::size_type start = 0); |
626 | | Foundation_API std::string replace(const std::string& str, const std::string::value_type from, const std::string::value_type to = 0, std::string::size_type start = 0); |
627 | | Foundation_API std::string remove(const std::string& str, const std::string::value_type ch, std::string::size_type start = 0); |
628 | | Foundation_API std::string& replaceInPlace(std::string& str, const std::string& from, const std::string& to, std::string::size_type start = 0); |
629 | | Foundation_API std::string& replaceInPlace(std::string& str, const std::string::value_type* from, const std::string::value_type* to, std::string::size_type start = 0); |
630 | | Foundation_API std::string& replaceInPlace(std::string& str, const std::string::value_type from, const std::string::value_type to = 0, std::string::size_type start = 0); |
631 | | Foundation_API std::string& removeInPlace(std::string& str, const std::string::value_type ch, std::string::size_type start = 0); |
632 | | |
633 | | |
634 | | #endif |
635 | | |
636 | | |
637 | | template <class S> |
638 | | S cat(const S& s1, const S& s2) |
639 | | /// Concatenates two strings. |
640 | | { |
641 | | S result = s1; |
642 | | result.reserve(s1.size() + s2.size()); |
643 | | result.append(s2); |
644 | | return result; |
645 | | } |
646 | | |
647 | | |
648 | | template <class S> |
649 | | S cat(const S& s1, const S& s2, const S& s3) |
650 | | /// Concatenates three strings. |
651 | | { |
652 | | S result = s1; |
653 | | result.reserve(s1.size() + s2.size() + s3.size()); |
654 | | result.append(s2); |
655 | | result.append(s3); |
656 | | return result; |
657 | | } |
658 | | |
659 | | |
660 | | template <class S> |
661 | | S cat(const S& s1, const S& s2, const S& s3, const S& s4) |
662 | | /// Concatenates four strings. |
663 | | { |
664 | | S result = s1; |
665 | | result.reserve(s1.size() + s2.size() + s3.size() + s4.size()); |
666 | | result.append(s2); |
667 | | result.append(s3); |
668 | | result.append(s4); |
669 | | return result; |
670 | | } |
671 | | |
672 | | |
673 | | template <class S> |
674 | | S cat(const S& s1, const S& s2, const S& s3, const S& s4, const S& s5) |
675 | | /// Concatenates five strings. |
676 | | { |
677 | | S result = s1; |
678 | | result.reserve(s1.size() + s2.size() + s3.size() + s4.size() + s5.size()); |
679 | | result.append(s2); |
680 | | result.append(s3); |
681 | | result.append(s4); |
682 | | result.append(s5); |
683 | | return result; |
684 | | } |
685 | | |
686 | | |
687 | | template <class S> |
688 | | S cat(const S& s1, const S& s2, const S& s3, const S& s4, const S& s5, const S& s6) |
689 | | /// Concatenates six strings. |
690 | | { |
691 | | S result = s1; |
692 | | result.reserve(s1.size() + s2.size() + s3.size() + s4.size() + s5.size() + s6.size()); |
693 | | result.append(s2); |
694 | | result.append(s3); |
695 | | result.append(s4); |
696 | | result.append(s5); |
697 | | result.append(s6); |
698 | | return result; |
699 | | } |
700 | | |
701 | | |
702 | | template <class S, class It> |
703 | | S cat(const S& delim, const It& begin, const It& end) |
704 | | /// Concatenates a sequence of strings, delimited |
705 | | /// by the string given in delim. |
706 | | { |
707 | | S result; |
708 | | for (It it = begin; it != end; ++it) |
709 | | { |
710 | | if (!result.empty()) result.append(delim); |
711 | | result += *it; |
712 | | } |
713 | | return result; |
714 | | } |
715 | | |
716 | | |
717 | | template <class S> |
718 | | bool startsWith(const S& str, const S& prefix) |
719 | | /// Tests whether the string starts with the given prefix. |
720 | | { |
721 | | return str.size() >= prefix.size() && equal(prefix.begin(), prefix.end(), str.begin()); |
722 | | } |
723 | | |
724 | | |
725 | | template <class S> |
726 | | bool endsWith(const S& str, const S& suffix) |
727 | | /// Tests whether the string ends with the given suffix. |
728 | | { |
729 | | return str.size() >= suffix.size() && equal(suffix.rbegin(), suffix.rend(), str.rbegin()); |
730 | | } |
731 | | |
732 | | |
733 | | // |
734 | | // case-insensitive string equality |
735 | | // |
736 | | |
737 | | |
738 | | template <typename charT> |
739 | | struct i_char_traits : public std::char_traits<charT> |
740 | | { |
741 | | inline static bool eq(charT c1, charT c2) |
742 | | { |
743 | | return Ascii::toLower(c1) == Ascii::toLower(c2); |
744 | | } |
745 | | |
746 | | inline static bool ne(charT c1, charT c2) |
747 | | { |
748 | | return !eq(c1, c2); |
749 | | } |
750 | | |
751 | | inline static bool lt(charT c1, charT c2) |
752 | | { |
753 | | return Ascii::toLower(c1) < Ascii::toLower(c2); |
754 | | } |
755 | | |
756 | | static int compare(const charT* s1, const charT* s2, std::size_t n) |
757 | | { |
758 | | for (int i = 0; i < n && s1 && s2; ++i, ++s1, ++s2) |
759 | | { |
760 | | if (Ascii::toLower(*s1) == Ascii::toLower(*s2)) continue; |
761 | | else if (Ascii::toLower(*s1) < Ascii::toLower(*s2)) return -1; |
762 | | else return 1; |
763 | | } |
764 | | |
765 | | return 0; |
766 | | } |
767 | | |
768 | | static const charT* find(const charT* s, int n, charT a) |
769 | | { |
770 | | while(n-- > 0 && Ascii::toLower(*s) != Ascii::toLower(a)) { ++s; } |
771 | | return s; |
772 | | } |
773 | | }; |
774 | | |
775 | | |
776 | | using istring = std::basic_string<char, i_char_traits<char>>; |
777 | | /// Case-insensitive std::string counterpart. |
778 | | |
779 | | |
780 | | template<typename T> |
781 | | std::size_t isubstr(const T& str, const T& sought) |
782 | | /// Case-insensitive substring; searches for a substring |
783 | | /// without regards to case. |
784 | | { |
785 | | typename T::const_iterator it = std::search(str.begin(), str.end(), |
786 | | sought.begin(), sought.end(), |
787 | | i_char_traits<typename T::value_type>::eq); |
788 | | |
789 | | if (it != str.end()) return it - str.begin(); |
790 | | else return static_cast<std::size_t>(T::npos); |
791 | | } |
792 | | |
793 | | |
794 | | struct CILess |
795 | | /// Case-insensitive less-than functor; useful for standard maps |
796 | | /// and sets with std::strings keys and case-insensitive ordering |
797 | | /// requirement. |
798 | | { |
799 | | inline bool operator() (const std::string& s1, const std::string& s2) const |
800 | 147k | { |
801 | 147k | return icompare(s1, s2) < 0; |
802 | 147k | } |
803 | | }; |
804 | | |
805 | | |
806 | | template <typename T> |
807 | | void secureClear(T& str) |
808 | | /// Securely clears a string's contents by first overwriting |
809 | | /// the entire buffer (up to capacity) with zeroes, then |
810 | | /// clearing the string. |
811 | 0 | { |
812 | 0 | str.resize(str.capacity()); |
813 | 0 | std::fill(str.begin(), str.end(), typename T::value_type()); |
814 | 0 | str.clear(); |
815 | 0 | } |
816 | | |
817 | | |
818 | | } // namespace Poco |
819 | | |
820 | | |
821 | | #if defined(__clang__) && ((__clang_major__ > 3) || (__clang_major__ == 3 && __clang_minor__ >= 6)) |
822 | | # pragma clang diagnostic pop |
823 | | #endif |
824 | | |
825 | | |
826 | | #endif // Foundation_String_INCLUDED |