String.h 17 KB

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