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 | #include <algorithm> |
25 | |
26 | |
27 | namespace Poco { |
28 | |
29 | |
30 | template <class S> |
31 | S trimLeft(const S& str) |
32 | /// Returns a copy of str with all leading |
33 | /// whitespace removed. |
34 | { |
35 | typename S::const_iterator it = str.begin(); |
36 | typename S::const_iterator end = str.end(); |
37 | |
38 | while (it != end && Ascii::isSpace(*it)) ++it; |
39 | return S(it, end); |
40 | } |
41 | |
42 | |
43 | template <class S> |
44 | S& trimLeftInPlace(S& str) |
45 | /// Removes all leading whitespace in str. |
46 | { |
47 | typename S::iterator it = str.begin(); |
48 | typename S::iterator end = str.end(); |
49 | |
50 | while (it != end && Ascii::isSpace(*it)) ++it; |
51 | str.erase(str.begin(), it); |
52 | return str; |
53 | } |
54 | |
55 | |
56 | template <class S> |
57 | S trimRight(const S& str) |
58 | /// Returns a copy of str with all trailing |
59 | /// whitespace removed. |
60 | { |
61 | int pos = int(str.size()) - 1; |
62 | |
63 | while (pos >= 0 && Ascii::isSpace(str[pos])) --pos; |
64 | return S(str, 0, pos + 1); |
65 | } |
66 | |
67 | |
68 | template <class S> |
69 | S& trimRightInPlace(S& str) |
70 | /// Removes all trailing whitespace in str. |
71 | { |
72 | int pos = int(str.size()) - 1; |
73 | |
74 | while (pos >= 0 && Ascii::isSpace(str[pos])) --pos; |
75 | str.resize(pos + 1); |
76 | |
77 | return str; |
78 | } |
79 | |
80 | |
81 | template <class S> |
82 | S trim(const S& str) |
83 | /// Returns a copy of str with all leading and |
84 | /// trailing whitespace removed. |
85 | { |
86 | int first = 0; |
87 | int last = int(str.size()) - 1; |
88 | |
89 | while (first <= last && Ascii::isSpace(str[first])) ++first; |
90 | while (last >= first && Ascii::isSpace(str[last])) --last; |
91 | |
92 | return S(str, first, last - first + 1); |
93 | } |
94 | |
95 | |
96 | template <class S> |
97 | S& trimInPlace(S& str) |
98 | /// Removes all leading and trailing whitespace in str. |
99 | { |
100 | int first = 0; |
101 | int last = int(str.size()) - 1; |
102 | |
103 | while (first <= last && Ascii::isSpace(str[first])) ++first; |
104 | while (last >= first && Ascii::isSpace(str[last])) --last; |
105 | |
106 | str.resize(last + 1); |
107 | str.erase(0, first); |
108 | |
109 | return str; |
110 | } |
111 | |
112 | |
113 | template <class S> |
114 | S toUpper(const S& str) |
115 | /// Returns a copy of str containing all upper-case characters. |
116 | { |
117 | typename S::const_iterator it = str.begin(); |
118 | typename S::const_iterator end = str.end(); |
119 | |
120 | S result; |
121 | result.reserve(str.size()); |
122 | while (it != end) result += static_cast<typename S::value_type>(Ascii::toUpper(*it++)); |
123 | return result; |
124 | } |
125 | |
126 | |
127 | template <class S> |
128 | S& toUpperInPlace(S& str) |
129 | /// Replaces all characters in str with their upper-case counterparts. |
130 | { |
131 | typename S::iterator it = str.begin(); |
132 | typename S::iterator end = str.end(); |
133 | |
134 | while (it != end) { *it = static_cast<typename S::value_type>(Ascii::toUpper(*it)); ++it; } |
135 | return str; |
136 | } |
137 | |
138 | |
139 | template <class S> |
140 | S toLower(const S& str) |
141 | /// Returns a copy of str containing all lower-case characters. |
142 | { |
143 | typename S::const_iterator it = str.begin(); |
144 | typename S::const_iterator end = str.end(); |
145 | |
146 | S result; |
147 | result.reserve(str.size()); |
148 | while (it != end) result += static_cast<typename S::value_type>(Ascii::toLower(*it++)); |
149 | return result; |
150 | } |
151 | |
152 | |
153 | template <class S> |
154 | S& toLowerInPlace(S& str) |
155 | /// Replaces all characters in str with their lower-case counterparts. |
156 | { |
157 | typename S::iterator it = str.begin(); |
158 | typename S::iterator end = str.end(); |
159 | |
160 | while (it != end) { *it = static_cast<typename S::value_type>(Ascii::toLower(*it)); ++it; } |
161 | return str; |
162 | } |
163 | |
164 | |
165 | #if !defined(POCO_NO_TEMPLATE_ICOMPARE) |
166 | |
167 | |
168 | template <class S, class It> |
169 | int icompare( |
170 | const S& str, |
171 | typename S::size_type pos, |
172 | typename S::size_type n, |
173 | It it2, |
174 | It end2) |
175 | /// Case-insensitive string comparison |
176 | { |
177 | typename S::size_type sz = str.size(); |
178 | if (pos > sz) pos = sz; |
179 | if (pos + n > sz) n = sz - pos; |
180 | It it1 = str.begin() + pos; |
181 | It end1 = str.begin() + pos + n; |
182 | while (it1 != end1 && it2 != end2) |
183 | { |
184 | typename S::value_type c1(static_cast<typename S::value_type>(Ascii::toLower(*it1))); |
185 | typename S::value_type c2(static_cast<typename S::value_type>(Ascii::toLower(*it2))); |
186 | if (c1 < c2) |
187 | return -1; |
188 | else if (c1 > c2) |
189 | return 1; |
190 | ++it1; ++it2; |
191 | } |
192 | |
193 | if (it1 == end1) |
194 | return it2 == end2 ? 0 : -1; |
195 | else |
196 | return 1; |
197 | } |
198 | |
199 | |
200 | template <class S> |
201 | int icompare(const S& str1, const S& str2) |
202 | // A special optimization for an often used case. |
203 | { |
204 | typename S::const_iterator it1(str1.begin()); |
205 | typename S::const_iterator end1(str1.end()); |
206 | typename S::const_iterator it2(str2.begin()); |
207 | typename S::const_iterator end2(str2.end()); |
208 | while (it1 != end1 && it2 != end2) |
209 | { |
210 | typename S::value_type c1(static_cast<typename S::value_type>(Ascii::toLower(*it1))); |
211 | typename S::value_type c2(static_cast<typename S::value_type>(Ascii::toLower(*it2))); |
212 | if (c1 < c2) |
213 | return -1; |
214 | else if (c1 > c2) |
215 | return 1; |
216 | ++it1; ++it2; |
217 | } |
218 | |
219 | if (it1 == end1) |
220 | return it2 == end2 ? 0 : -1; |
221 | else |
222 | return 1; |
223 | } |
224 | |
225 | |
226 | template <class S> |
227 | int icompare(const S& str1, typename S::size_type n1, const S& str2, typename S::size_type n2) |
228 | { |
229 | if (n2 > str2.size()) n2 = str2.size(); |
230 | return icompare(str1, 0, n1, str2.begin(), str2.begin() + n2); |
231 | } |
232 | |
233 | |
234 | template <class S> |
235 | int icompare(const S& str1, typename S::size_type n, const S& str2) |
236 | { |
237 | if (n > str2.size()) n = str2.size(); |
238 | return icompare(str1, 0, n, str2.begin(), str2.begin() + n); |
239 | } |
240 | |
241 | |
242 | template <class S> |
243 | int icompare(const S& str1, typename S::size_type pos, typename S::size_type n, const S& str2) |
244 | { |
245 | return icompare(str1, pos, n, str2.begin(), str2.end()); |
246 | } |
247 | |
248 | |
249 | template <class S> |
250 | int icompare( |
251 | const S& str1, |
252 | typename S::size_type pos1, |
253 | typename S::size_type n1, |
254 | const S& str2, |
255 | typename S::size_type pos2, |
256 | typename S::size_type n2) |
257 | { |
258 | typename S::size_type sz2 = str2.size(); |
259 | if (pos2 > sz2) pos2 = sz2; |
260 | if (pos2 + n2 > sz2) n2 = sz2 - pos2; |
261 | return icompare(str1, pos1, n1, str2.begin() + pos2, str2.begin() + pos2 + n2); |
262 | } |
263 | |
264 | |
265 | template <class S> |
266 | int icompare( |
267 | const S& str1, |
268 | typename S::size_type pos1, |
269 | typename S::size_type n, |
270 | const S& str2, |
271 | typename S::size_type pos2) |
272 | { |
273 | typename S::size_type sz2 = str2.size(); |
274 | if (pos2 > sz2) pos2 = sz2; |
275 | if (pos2 + n > sz2) n = sz2 - pos2; |
276 | return icompare(str1, pos1, n, str2.begin() + pos2, str2.begin() + pos2 + n); |
277 | } |
278 | |
279 | |
280 | template <class S> |
281 | int icompare( |
282 | const S& str, |
283 | typename S::size_type pos, |
284 | typename S::size_type n, |
285 | const typename S::value_type* ptr) |
286 | { |
287 | poco_check_ptr (ptr); |
288 | typename S::size_type sz = str.size(); |
289 | if (pos > sz) pos = sz; |
290 | if (pos + n > sz) n = sz - pos; |
291 | typename S::const_iterator it = str.begin() + pos; |
292 | typename S::const_iterator end = str.begin() + pos + n; |
293 | while (it != end && *ptr) |
294 | { |
295 | typename S::value_type c1(static_cast<typename S::value_type>(Ascii::toLower(*it))); |
296 | typename S::value_type c2(static_cast<typename S::value_type>(Ascii::toLower(*ptr))); |
297 | if (c1 < c2) |
298 | return -1; |
299 | else if (c1 > c2) |
300 | return 1; |
301 | ++it; ++ptr; |
302 | } |
303 | |
304 | if (it == end) |
305 | return *ptr == 0 ? 0 : -1; |
306 | else |
307 | return 1; |
308 | } |
309 | |
310 | |
311 | template <class S> |
312 | int icompare( |
313 | const S& str, |
314 | typename S::size_type pos, |
315 | const typename S::value_type* ptr) |
316 | { |
317 | return icompare(str, pos, str.size() - pos, ptr); |
318 | } |
319 | |
320 | |
321 | template <class S> |
322 | int icompare( |
323 | const S& str, |
324 | const typename S::value_type* ptr) |
325 | { |
326 | return icompare(str, 0, str.size(), ptr); |
327 | } |
328 | |
329 | |
330 | #else |
331 | |
332 | |
333 | 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); |
334 | int Foundation_API icompare(const std::string& str1, const std::string& str2); |
335 | int Foundation_API icompare(const std::string& str1, std::string::size_type n1, const std::string& str2, std::string::size_type n2); |
336 | int Foundation_API icompare(const std::string& str1, std::string::size_type n, const std::string& str2); |
337 | int Foundation_API icompare(const std::string& str1, std::string::size_type pos, std::string::size_type n, const std::string& str2); |
338 | 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); |
339 | 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); |
340 | int Foundation_API icompare(const std::string& str, std::string::size_type pos, std::string::size_type n, const std::string::value_type* ptr); |
341 | int Foundation_API icompare(const std::string& str, std::string::size_type pos, const std::string::value_type* ptr); |
342 | int Foundation_API icompare(const std::string& str, const std::string::value_type* ptr); |
343 | |
344 | |
345 | #endif |
346 | |
347 | |
348 | template <class S> |
349 | S translate(const S& str, const S& from, const S& to) |
350 | /// Returns a copy of str with all characters in |
351 | /// from replaced by the corresponding (by position) |
352 | /// characters in to. If there is no corresponding |
353 | /// character in to, the character is removed from |
354 | /// the copy. |
355 | { |
356 | S result; |
357 | result.reserve(str.size()); |
358 | typename S::const_iterator it = str.begin(); |
359 | typename S::const_iterator end = str.end(); |
360 | typename S::size_type toSize = to.size(); |
361 | while (it != end) |
362 | { |
363 | typename S::size_type pos = from.find(*it); |
364 | if (pos == S::npos) |
365 | { |
366 | result += *it; |
367 | } |
368 | else |
369 | { |
370 | if (pos < toSize) result += to[pos]; |
371 | } |
372 | ++it; |
373 | } |
374 | return result; |
375 | } |
376 | |
377 | |
378 | template <class S> |
379 | S translate(const S& str, const typename S::value_type* from, const typename S::value_type* to) |
380 | { |
381 | poco_check_ptr (from); |
382 | poco_check_ptr (to); |
383 | return translate(str, S(from), S(to)); |
384 | } |
385 | |
386 | |
387 | template <class S> |
388 | S& translateInPlace(S& str, const S& from, const S& to) |
389 | /// Replaces in str all occurrences of characters in from |
390 | /// with the corresponding (by position) characters in to. |
391 | /// If there is no corresponding character, the character |
392 | /// is removed. |
393 | { |
394 | str = translate(str, from, to); |
395 | return str; |
396 | } |
397 | |
398 | |
399 | template <class S> |
400 | S translateInPlace(S& str, const typename S::value_type* from, const typename S::value_type* to) |
401 | { |
402 | poco_check_ptr (from); |
403 | poco_check_ptr (to); |
404 | str = translate(str, S(from), S(to)); |
405 | #if defined(__SUNPRO_CC) |
406 | // Fix around the RVO bug in SunStudio 12.4 |
407 | S ret(str); |
408 | return ret; |
409 | #else |
410 | return str; |
411 | #endif |
412 | } |
413 | |
414 | |
415 | #if !defined(POCO_NO_TEMPLATE_ICOMPARE) |
416 | |
417 | |
418 | template <class S> |
419 | S& replaceInPlace(S& str, const S& from, const S& to, typename S::size_type start = 0) |
420 | { |
421 | poco_assert (from.size() > 0); |
422 | |
423 | S result; |
424 | typename S::size_type pos = 0; |
425 | result.append(str, 0, start); |
426 | do |
427 | { |
428 | pos = str.find(from, start); |
429 | if (pos != S::npos) |
430 | { |
431 | result.append(str, start, pos - start); |
432 | result.append(to); |
433 | start = pos + from.length(); |
434 | } |
435 | else result.append(str, start, str.size() - start); |
436 | } |
437 | while (pos != S::npos); |
438 | str.swap(result); |
439 | return str; |
440 | } |
441 | |
442 | |
443 | template <class S> |
444 | S& replaceInPlace(S& str, const typename S::value_type* from, const typename S::value_type* to, typename S::size_type start = 0) |
445 | { |
446 | poco_assert (*from); |
447 | |
448 | S result; |
449 | typename S::size_type pos = 0; |
450 | typename S::size_type fromLen = std::strlen(from); |
451 | result.append(str, 0, start); |
452 | do |
453 | { |
454 | pos = str.find(from, start); |
455 | if (pos != S::npos) |
456 | { |
457 | result.append(str, start, pos - start); |
458 | result.append(to); |
459 | start = pos + fromLen; |
460 | } |
461 | else result.append(str, start, str.size() - start); |
462 | } |
463 | while (pos != S::npos); |
464 | str.swap(result); |
465 | return str; |
466 | } |
467 | |
468 | |
469 | template <class S> |
470 | S& replaceInPlace(S& str, const typename S::value_type from, const typename S::value_type to = 0, typename S::size_type start = 0) |
471 | { |
472 | if (from == to) return str; |
473 | |
474 | typename S::size_type pos = 0; |
475 | do |
476 | { |
477 | pos = str.find(from, start); |
478 | if (pos != S::npos) |
479 | { |
480 | if (to) str[pos] = to; |
481 | else str.erase(pos, 1); |
482 | } |
483 | } while (pos != S::npos); |
484 | |
485 | return str; |
486 | } |
487 | |
488 | |
489 | template <class S> |
490 | S& removeInPlace(S& str, const typename S::value_type ch, typename S::size_type start = 0) |
491 | { |
492 | return replaceInPlace(str, ch, 0, start); |
493 | } |
494 | |
495 | |
496 | template <class S> |
497 | S replace(const S& str, const S& from, const S& to, typename S::size_type start = 0) |
498 | /// Replace all occurrences of from (which must not be the empty string) |
499 | /// in str with to, starting at position start. |
500 | { |
501 | S result(str); |
502 | replaceInPlace(result, from, to, start); |
503 | return result; |
504 | } |
505 | |
506 | |
507 | template <class S> |
508 | S replace(const S& str, const typename S::value_type* from, const typename S::value_type* to, typename S::size_type start = 0) |
509 | { |
510 | S result(str); |
511 | replaceInPlace(result, from, to, start); |
512 | return result; |
513 | } |
514 | |
515 | |
516 | template <class S> |
517 | S replace(const S& str, const typename S::value_type from, const typename S::value_type to = 0, typename S::size_type start = 0) |
518 | { |
519 | S result(str); |
520 | replaceInPlace(result, from, to, start); |
521 | return result; |
522 | } |
523 | |
524 | |
525 | template <class S> |
526 | S remove(const S& str, const typename S::value_type ch, typename S::size_type start = 0) |
527 | { |
528 | S result(str); |
529 | replaceInPlace(result, ch, 0, start); |
530 | return result; |
531 | } |
532 | |
533 | |
534 | #else |
535 | |
536 | |
537 | Foundation_API std::string replace(const std::string& str, const std::string& from, const std::string& to, std::string::size_type start = 0); |
538 | 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); |
539 | 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); |
540 | Foundation_API std::string remove(const std::string& str, const std::string::value_type ch, std::string::size_type start = 0); |
541 | Foundation_API std::string& replaceInPlace(std::string& str, const std::string& from, const std::string& to, std::string::size_type start = 0); |
542 | 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); |
543 | 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); |
544 | Foundation_API std::string& removeInPlace(std::string& str, const std::string::value_type ch, std::string::size_type start = 0); |
545 | |
546 | |
547 | #endif |
548 | |
549 | |
550 | template <class S> |
551 | S cat(const S& s1, const S& s2) |
552 | /// Concatenates two strings. |
553 | { |
554 | S result = s1; |
555 | result.reserve(s1.size() + s2.size()); |
556 | result.append(s2); |
557 | return result; |
558 | } |
559 | |
560 | |
561 | template <class S> |
562 | S cat(const S& s1, const S& s2, const S& s3) |
563 | /// Concatenates three strings. |
564 | { |
565 | S result = s1; |
566 | result.reserve(s1.size() + s2.size() + s3.size()); |
567 | result.append(s2); |
568 | result.append(s3); |
569 | return result; |
570 | } |
571 | |
572 | |
573 | template <class S> |
574 | S cat(const S& s1, const S& s2, const S& s3, const S& s4) |
575 | /// Concatenates four strings. |
576 | { |
577 | S result = s1; |
578 | result.reserve(s1.size() + s2.size() + s3.size() + s4.size()); |
579 | result.append(s2); |
580 | result.append(s3); |
581 | result.append(s4); |
582 | return result; |
583 | } |
584 | |
585 | |
586 | template <class S> |
587 | S cat(const S& s1, const S& s2, const S& s3, const S& s4, const S& s5) |
588 | /// Concatenates five strings. |
589 | { |
590 | S result = s1; |
591 | result.reserve(s1.size() + s2.size() + s3.size() + s4.size() + s5.size()); |
592 | result.append(s2); |
593 | result.append(s3); |
594 | result.append(s4); |
595 | result.append(s5); |
596 | return result; |
597 | } |
598 | |
599 | |
600 | template <class S> |
601 | S cat(const S& s1, const S& s2, const S& s3, const S& s4, const S& s5, const S& s6) |
602 | /// Concatenates six strings. |
603 | { |
604 | S result = s1; |
605 | result.reserve(s1.size() + s2.size() + s3.size() + s4.size() + s5.size() + s6.size()); |
606 | result.append(s2); |
607 | result.append(s3); |
608 | result.append(s4); |
609 | result.append(s5); |
610 | result.append(s6); |
611 | return result; |
612 | } |
613 | |
614 | |
615 | template <class S, class It> |
616 | S cat(const S& delim, const It& begin, const It& end) |
617 | /// Concatenates a sequence of strings, delimited |
618 | /// by the string given in delim. |
619 | { |
620 | S result; |
621 | for (It it = begin; it != end; ++it) |
622 | { |
623 | if (!result.empty()) result.append(delim); |
624 | result += *it; |
625 | } |
626 | return result; |
627 | } |
628 | |
629 | |
630 | template <class S> |
631 | bool startsWith(const S& str, const S& prefix) |
632 | /// Tests whether the string starts with the given prefix. |
633 | { |
634 | return str.size() >= prefix.size() && equal(prefix.begin(), prefix.end(), str.begin()); |
635 | } |
636 | |
637 | |
638 | template <class S> |
639 | bool endsWith(const S& str, const S& suffix) |
640 | /// Tests whether the string ends with the given suffix. |
641 | { |
642 | return str.size() >= suffix.size() && equal(suffix.rbegin(), suffix.rend(), str.rbegin()); |
643 | } |
644 | |
645 | |
646 | // |
647 | // case-insensitive string equality |
648 | // |
649 | |
650 | |
651 | template <typename charT> |
652 | struct i_char_traits : public std::char_traits<charT> |
653 | { |
654 | inline static bool eq(charT c1, charT c2) |
655 | { |
656 | return Ascii::toLower(c1) == Ascii::toLower(c2); |
657 | } |
658 | |
659 | inline static bool ne(charT c1, charT c2) |
660 | { |
661 | return !eq(c1, c2); |
662 | } |
663 | |
664 | inline static bool lt(charT c1, charT c2) |
665 | { |
666 | return Ascii::toLower(c1) < Ascii::toLower(c2); |
667 | } |
668 | |
669 | static int compare(const charT* s1, const charT* s2, std::size_t n) |
670 | { |
671 | for (int i = 0; i < n && s1 && s2; ++i, ++s1, ++s2) |
672 | { |
673 | if (Ascii::toLower(*s1) == Ascii::toLower(*s2)) continue; |
674 | else if (Ascii::toLower(*s1) < Ascii::toLower(*s2)) return -1; |
675 | else return 1; |
676 | } |
677 | |
678 | return 0; |
679 | } |
680 | |
681 | static const charT* find(const charT* s, int n, charT a) |
682 | { |
683 | while(n-- > 0 && Ascii::toLower(*s) != Ascii::toLower(a)) { ++s; } |
684 | return s; |
685 | } |
686 | }; |
687 | |
688 | |
689 | typedef std::basic_string<char, i_char_traits<char> > istring; |
690 | /// Case-insensitive std::string counterpart. |
691 | |
692 | |
693 | template<typename T> |
694 | std::size_t isubstr(const T& str, const T& sought) |
695 | /// Case-insensitive substring; searches for a substring |
696 | /// without regards to case. |
697 | { |
698 | typename T::const_iterator it = std::search(str.begin(), str.end(), |
699 | sought.begin(), sought.end(), |
700 | i_char_traits<typename T::value_type>::eq); |
701 | |
702 | if (it != str.end()) return it - str.begin(); |
703 | else return static_cast<std::size_t>(T::npos); |
704 | } |
705 | |
706 | |
707 | struct CILess |
708 | /// Case-insensitive less-than functor; useful for standard maps |
709 | /// and sets with std::strings keys and case-insensitive ordering |
710 | /// requirement. |
711 | { |
712 | inline bool operator() (const std::string& s1, const std::string& s2) const |
713 | { |
714 | return icompare(s1, s2) < 0; |
715 | } |
716 | }; |
717 | |
718 | |
719 | } // namespace Poco |
720 | |
721 | |
722 | #endif // Foundation_String_INCLUDED |
723 | |