String.h 17 KB

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