String.h 19 KB

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