123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706 |
- //
- // String.h
- //
- // Library: Foundation
- // Package: Core
- // Module: String
- //
- // String utility functions.
- //
- // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
- // and Contributors.
- //
- // SPDX-License-Identifier: BSL-1.0
- //
- #ifndef Foundation_String_INCLUDED
- #define Foundation_String_INCLUDED
- #include "Poco/Foundation.h"
- #include "Poco/Ascii.h"
- #include <cstring>
- #include <algorithm>
- namespace Poco {
- template <class S>
- S trimLeft(const S& str)
- /// Returns a copy of str with all leading
- /// whitespace removed.
- {
- typename S::const_iterator it = str.begin();
- typename S::const_iterator end = str.end();
- while (it != end && Ascii::isSpace(*it)) ++it;
- return S(it, end);
- }
- template <class S>
- S& trimLeftInPlace(S& str)
- /// Removes all leading whitespace in str.
- {
- typename S::iterator it = str.begin();
- typename S::iterator end = str.end();
- while (it != end && Ascii::isSpace(*it)) ++it;
- str.erase(str.begin(), it);
- return str;
- }
- template <class S>
- S trimRight(const S& str)
- /// Returns a copy of str with all trailing
- /// whitespace removed.
- {
- int pos = int(str.size()) - 1;
- while (pos >= 0 && Ascii::isSpace(str[pos])) --pos;
- return S(str, 0, pos + 1);
- }
- template <class S>
- S& trimRightInPlace(S& str)
- /// Removes all trailing whitespace in str.
- {
- int pos = int(str.size()) - 1;
- while (pos >= 0 && Ascii::isSpace(str[pos])) --pos;
- str.resize(pos + 1);
- return str;
- }
- template <class S>
- S trim(const S& str)
- /// Returns a copy of str with all leading and
- /// trailing whitespace removed.
- {
- int first = 0;
- int last = int(str.size()) - 1;
- while (first <= last && Ascii::isSpace(str[first])) ++first;
- while (last >= first && Ascii::isSpace(str[last])) --last;
- return S(str, first, last - first + 1);
- }
- template <class S>
- S& trimInPlace(S& str)
- /// Removes all leading and trailing whitespace in str.
- {
- int first = 0;
- int last = int(str.size()) - 1;
- while (first <= last && Ascii::isSpace(str[first])) ++first;
- while (last >= first && Ascii::isSpace(str[last])) --last;
- str.resize(last + 1);
- str.erase(0, first);
- return str;
- }
- template <class S>
- S toUpper(const S& str)
- /// Returns a copy of str containing all upper-case characters.
- {
- typename S::const_iterator it = str.begin();
- typename S::const_iterator end = str.end();
- S result;
- result.reserve(str.size());
- while (it != end) result += static_cast<typename S::value_type>(Ascii::toUpper(*it++));
- return result;
- }
- template <class S>
- S& toUpperInPlace(S& str)
- /// Replaces all characters in str with their upper-case counterparts.
- {
- typename S::iterator it = str.begin();
- typename S::iterator end = str.end();
- while (it != end) { *it = static_cast<typename S::value_type>(Ascii::toUpper(*it)); ++it; }
- return str;
- }
- template <class S>
- S toLower(const S& str)
- /// Returns a copy of str containing all lower-case characters.
- {
- typename S::const_iterator it = str.begin();
- typename S::const_iterator end = str.end();
- S result;
- result.reserve(str.size());
- while (it != end) result += static_cast<typename S::value_type>(Ascii::toLower(*it++));
- return result;
- }
- template <class S>
- S& toLowerInPlace(S& str)
- /// Replaces all characters in str with their lower-case counterparts.
- {
- typename S::iterator it = str.begin();
- typename S::iterator end = str.end();
- while (it != end) { *it = static_cast<typename S::value_type>(Ascii::toLower(*it)); ++it; }
- return str;
- }
- #if !defined(POCO_NO_TEMPLATE_ICOMPARE)
- template <class S, class It>
- int icompare(
- const S& str,
- typename S::size_type pos,
- typename S::size_type n,
- It it2,
- It end2)
- /// Case-insensitive string comparison
- {
- typename S::size_type sz = str.size();
- if (pos > sz) pos = sz;
- if (pos + n > sz) n = sz - pos;
- It it1 = str.begin() + pos;
- It end1 = str.begin() + pos + n;
- while (it1 != end1 && it2 != end2)
- {
- typename S::value_type c1(static_cast<typename S::value_type>(Ascii::toLower(*it1)));
- typename S::value_type c2(static_cast<typename S::value_type>(Ascii::toLower(*it2)));
- if (c1 < c2)
- return -1;
- else if (c1 > c2)
- return 1;
- ++it1; ++it2;
- }
- if (it1 == end1)
- return it2 == end2 ? 0 : -1;
- else
- return 1;
- }
- template <class S>
- int icompare(const S& str1, const S& str2)
- // A special optimization for an often used case.
- {
- typename S::const_iterator it1(str1.begin());
- typename S::const_iterator end1(str1.end());
- typename S::const_iterator it2(str2.begin());
- typename S::const_iterator end2(str2.end());
- while (it1 != end1 && it2 != end2)
- {
- typename S::value_type c1(static_cast<typename S::value_type>(Ascii::toLower(*it1)));
- typename S::value_type c2(static_cast<typename S::value_type>(Ascii::toLower(*it2)));
- if (c1 < c2)
- return -1;
- else if (c1 > c2)
- return 1;
- ++it1; ++it2;
- }
- if (it1 == end1)
- return it2 == end2 ? 0 : -1;
- else
- return 1;
- }
- template <class S>
- int icompare(const S& str1, typename S::size_type n1, const S& str2, typename S::size_type n2)
- {
- if (n2 > str2.size()) n2 = str2.size();
- return icompare(str1, 0, n1, str2.begin(), str2.begin() + n2);
- }
- template <class S>
- int icompare(const S& str1, typename S::size_type n, const S& str2)
- {
- if (n > str2.size()) n = str2.size();
- return icompare(str1, 0, n, str2.begin(), str2.begin() + n);
- }
- template <class S>
- int icompare(const S& str1, typename S::size_type pos, typename S::size_type n, const S& str2)
- {
- return icompare(str1, pos, n, str2.begin(), str2.end());
- }
- template <class S>
- int icompare(
- const S& str1,
- typename S::size_type pos1,
- typename S::size_type n1,
- const S& str2,
- typename S::size_type pos2,
- typename S::size_type n2)
- {
- typename S::size_type sz2 = str2.size();
- if (pos2 > sz2) pos2 = sz2;
- if (pos2 + n2 > sz2) n2 = sz2 - pos2;
- return icompare(str1, pos1, n1, str2.begin() + pos2, str2.begin() + pos2 + n2);
- }
- template <class S>
- int icompare(
- const S& str1,
- typename S::size_type pos1,
- typename S::size_type n,
- const S& str2,
- typename S::size_type pos2)
- {
- typename S::size_type sz2 = str2.size();
- if (pos2 > sz2) pos2 = sz2;
- if (pos2 + n > sz2) n = sz2 - pos2;
- return icompare(str1, pos1, n, str2.begin() + pos2, str2.begin() + pos2 + n);
- }
- template <class S>
- int icompare(
- const S& str,
- typename S::size_type pos,
- typename S::size_type n,
- const typename S::value_type* ptr)
- {
- poco_check_ptr (ptr);
- typename S::size_type sz = str.size();
- if (pos > sz) pos = sz;
- if (pos + n > sz) n = sz - pos;
- typename S::const_iterator it = str.begin() + pos;
- typename S::const_iterator end = str.begin() + pos + n;
- while (it != end && *ptr)
- {
- typename S::value_type c1(static_cast<typename S::value_type>(Ascii::toLower(*it)));
- typename S::value_type c2(static_cast<typename S::value_type>(Ascii::toLower(*ptr)));
- if (c1 < c2)
- return -1;
- else if (c1 > c2)
- return 1;
- ++it; ++ptr;
- }
- if (it == end)
- return *ptr == 0 ? 0 : -1;
- else
- return 1;
- }
- template <class S>
- int icompare(
- const S& str,
- typename S::size_type pos,
- const typename S::value_type* ptr)
- {
- return icompare(str, pos, str.size() - pos, ptr);
- }
- template <class S>
- int icompare(
- const S& str,
- const typename S::value_type* ptr)
- {
- return icompare(str, 0, str.size(), ptr);
- }
- #else
- 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);
- int Foundation_API icompare(const std::string& str1, const std::string& str2);
- int Foundation_API icompare(const std::string& str1, std::string::size_type n1, const std::string& str2, std::string::size_type n2);
- int Foundation_API icompare(const std::string& str1, std::string::size_type n, const std::string& str2);
- int Foundation_API icompare(const std::string& str1, std::string::size_type pos, std::string::size_type n, const std::string& str2);
- 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);
- 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);
- int Foundation_API icompare(const std::string& str, std::string::size_type pos, std::string::size_type n, const std::string::value_type* ptr);
- int Foundation_API icompare(const std::string& str, std::string::size_type pos, const std::string::value_type* ptr);
- int Foundation_API icompare(const std::string& str, const std::string::value_type* ptr);
- #endif
- template <class S>
- S translate(const S& str, const S& from, const S& to)
- /// Returns a copy of str with all characters in
- /// from replaced by the corresponding (by position)
- /// characters in to. If there is no corresponding
- /// character in to, the character is removed from
- /// the copy.
- {
- S result;
- result.reserve(str.size());
- typename S::const_iterator it = str.begin();
- typename S::const_iterator end = str.end();
- typename S::size_type toSize = to.size();
- while (it != end)
- {
- typename S::size_type pos = from.find(*it);
- if (pos == S::npos)
- {
- result += *it;
- }
- else
- {
- if (pos < toSize) result += to[pos];
- }
- ++it;
- }
- return result;
- }
- template <class S>
- S translate(const S& str, const typename S::value_type* from, const typename S::value_type* to)
- {
- poco_check_ptr (from);
- poco_check_ptr (to);
- return translate(str, S(from), S(to));
- }
- template <class S>
- S& translateInPlace(S& str, const S& from, const S& to)
- /// Replaces in str all occurrences of characters in from
- /// with the corresponding (by position) characters in to.
- /// If there is no corresponding character, the character
- /// is removed.
- {
- str = translate(str, from, to);
- return str;
- }
- template <class S>
- S translateInPlace(S& str, const typename S::value_type* from, const typename S::value_type* to)
- {
- poco_check_ptr (from);
- poco_check_ptr (to);
- str = translate(str, S(from), S(to));
- #if defined(__SUNPRO_CC)
- // Fix around the RVO bug in SunStudio 12.4
- S ret(str);
- return ret;
- #else
- return str;
- #endif
- }
- #if !defined(POCO_NO_TEMPLATE_ICOMPARE)
- template <class S>
- S& replaceInPlace(S& str, const S& from, const S& to, typename S::size_type start = 0)
- {
- poco_assert (from.size() > 0);
- S result;
- typename S::size_type pos = 0;
- result.append(str, 0, start);
- do
- {
- pos = str.find(from, start);
- if (pos != S::npos)
- {
- result.append(str, start, pos - start);
- result.append(to);
- start = pos + from.length();
- }
- else result.append(str, start, str.size() - start);
- }
- while (pos != S::npos);
- str.swap(result);
- return str;
- }
- template <class S>
- S& replaceInPlace(S& str, const typename S::value_type* from, const typename S::value_type* to, typename S::size_type start = 0)
- {
- poco_assert (*from);
- S result;
- typename S::size_type pos = 0;
- typename S::size_type fromLen = std::strlen(from);
- result.append(str, 0, start);
- do
- {
- pos = str.find(from, start);
- if (pos != S::npos)
- {
- result.append(str, start, pos - start);
- result.append(to);
- start = pos + fromLen;
- }
- else result.append(str, start, str.size() - start);
- }
- while (pos != S::npos);
- str.swap(result);
- return str;
- }
- template <class S>
- S& replaceInPlace(S& str, const typename S::value_type from, const typename S::value_type to = 0, typename S::size_type start = 0)
- {
- if (from == to) return str;
- typename S::size_type pos = 0;
- do
- {
- pos = str.find(from, start);
- if (pos != S::npos)
- {
- if (to) str[pos] = to;
- else str.erase(pos, 1);
- }
- } while (pos != S::npos);
- return str;
- }
- template <class S>
- S& removeInPlace(S& str, const typename S::value_type ch, typename S::size_type start = 0)
- {
- return replaceInPlace(str, ch, 0, start);
- }
- template <class S>
- S replace(const S& str, const S& from, const S& to, typename S::size_type start = 0)
- /// Replace all occurrences of from (which must not be the empty string)
- /// in str with to, starting at position start.
- {
- S result(str);
- replaceInPlace(result, from, to, start);
- return result;
- }
- template <class S>
- S replace(const S& str, const typename S::value_type* from, const typename S::value_type* to, typename S::size_type start = 0)
- {
- S result(str);
- replaceInPlace(result, from, to, start);
- return result;
- }
- template <class S>
- S replace(const S& str, const typename S::value_type from, const typename S::value_type to = 0, typename S::size_type start = 0)
- {
- S result(str);
- replaceInPlace(result, from, to, start);
- return result;
- }
- template <class S>
- S remove(const S& str, const typename S::value_type ch, typename S::size_type start = 0)
- {
- S result(str);
- replaceInPlace(result, ch, 0, start);
- return result;
- }
- #else
- Foundation_API std::string replace(const std::string& str, const std::string& from, const std::string& to, std::string::size_type start = 0);
- 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);
- 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);
- Foundation_API std::string remove(const std::string& str, const std::string::value_type ch, std::string::size_type start = 0);
- Foundation_API std::string& replaceInPlace(std::string& str, const std::string& from, const std::string& to, std::string::size_type start = 0);
- 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);
- 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);
- Foundation_API std::string& removeInPlace(std::string& str, const std::string::value_type ch, std::string::size_type start = 0);
- #endif
- template <class S>
- S cat(const S& s1, const S& s2)
- /// Concatenates two strings.
- {
- S result = s1;
- result.reserve(s1.size() + s2.size());
- result.append(s2);
- return result;
- }
- template <class S>
- S cat(const S& s1, const S& s2, const S& s3)
- /// Concatenates three strings.
- {
- S result = s1;
- result.reserve(s1.size() + s2.size() + s3.size());
- result.append(s2);
- result.append(s3);
- return result;
- }
- template <class S>
- S cat(const S& s1, const S& s2, const S& s3, const S& s4)
- /// Concatenates four strings.
- {
- S result = s1;
- result.reserve(s1.size() + s2.size() + s3.size() + s4.size());
- result.append(s2);
- result.append(s3);
- result.append(s4);
- return result;
- }
- template <class S>
- S cat(const S& s1, const S& s2, const S& s3, const S& s4, const S& s5)
- /// Concatenates five strings.
- {
- S result = s1;
- result.reserve(s1.size() + s2.size() + s3.size() + s4.size() + s5.size());
- result.append(s2);
- result.append(s3);
- result.append(s4);
- result.append(s5);
- return result;
- }
- template <class S>
- S cat(const S& s1, const S& s2, const S& s3, const S& s4, const S& s5, const S& s6)
- /// Concatenates six strings.
- {
- S result = s1;
- result.reserve(s1.size() + s2.size() + s3.size() + s4.size() + s5.size() + s6.size());
- result.append(s2);
- result.append(s3);
- result.append(s4);
- result.append(s5);
- result.append(s6);
- return result;
- }
- template <class S, class It>
- S cat(const S& delim, const It& begin, const It& end)
- /// Concatenates a sequence of strings, delimited
- /// by the string given in delim.
- {
- S result;
- for (It it = begin; it != end; ++it)
- {
- if (!result.empty()) result.append(delim);
- result += *it;
- }
- return result;
- }
- //
- // case-insensitive string equality
- //
- template <typename charT>
- struct i_char_traits : public std::char_traits<charT>
- {
- inline static bool eq(charT c1, charT c2)
- {
- return Ascii::toLower(c1) == Ascii::toLower(c2);
- }
- inline static bool ne(charT c1, charT c2)
- {
- return !eq(c1, c2);
- }
- inline static bool lt(charT c1, charT c2)
- {
- return Ascii::toLower(c1) < Ascii::toLower(c2);
- }
- static int compare(const charT* s1, const charT* s2, std::size_t n)
- {
- for (int i = 0; i < n && s1 && s2; ++i, ++s1, ++s2)
- {
- if (Ascii::toLower(*s1) == Ascii::toLower(*s2)) continue;
- else if (Ascii::toLower(*s1) < Ascii::toLower(*s2)) return -1;
- else return 1;
- }
- return 0;
- }
- static const charT* find(const charT* s, int n, charT a)
- {
- while(n-- > 0 && Ascii::toLower(*s) != Ascii::toLower(a)) { ++s; }
- return s;
- }
- };
- typedef std::basic_string<char, i_char_traits<char> > istring;
- /// Case-insensitive std::string counterpart.
- template<typename T>
- std::size_t isubstr(const T& str, const T& sought)
- /// Case-insensitive substring; searches for a substring
- /// without regards to case.
- {
- typename T::const_iterator it = std::search(str.begin(), str.end(),
- sought.begin(), sought.end(),
- i_char_traits<typename T::value_type>::eq);
- if (it != str.end()) return it - str.begin();
- else return static_cast<std::size_t>(T::npos);
- }
- struct CILess
- /// Case-insensitive less-than functor; useful for standard maps
- /// and sets with std::strings keys and case-insensitive ordering
- /// requirement.
- {
- inline bool operator() (const std::string& s1, const std::string& s2) const
- {
- return icompare(s1, s2) < 0;
- }
- };
- } // namespace Poco
- #endif // Foundation_String_INCLUDED
|