+ wxString str;
+ int iPos = Find(ch, true);
+ if ( iPos == wxNOT_FOUND )
+ str = *this;
+ else
+ str.assign(*this, iPos + 1, npos);
+
+ return str;
+}
+
+// extract nCount first (leftmost) characters
+wxString wxString::Left(size_t nCount) const
+{
+ if ( nCount > length() )
+ nCount = length();
+
+ wxString dest(*this, 0, nCount);
+ if ( dest.length() != nCount ) {
+ wxFAIL_MSG( wxT("out of memory in wxString::Left") );
+ }
+ return dest;
+}
+
+// get all characters before the first occurrence of ch
+// (returns the whole string if ch not found)
+wxString wxString::BeforeFirst(wxUniChar ch, wxString *rest) const
+{
+ int iPos = Find(ch);
+ if ( iPos == wxNOT_FOUND )
+ {
+ iPos = length();
+ if ( rest )
+ rest->clear();
+ }
+ else
+ {
+ if ( rest )
+ rest->assign(*this, iPos + 1, npos);
+ }
+
+ return wxString(*this, 0, iPos);
+}
+
+/// get all characters before the last occurrence of ch
+/// (returns empty string if ch not found)
+wxString wxString::BeforeLast(wxUniChar ch, wxString *rest) const
+{
+ wxString str;
+ int iPos = Find(ch, true);
+ if ( iPos != wxNOT_FOUND )
+ {
+ if ( iPos != 0 )
+ str.assign(*this, 0, iPos);
+
+ if ( rest )
+ rest->assign(*this, iPos + 1, npos);
+ }
+ else
+ {
+ if ( rest )
+ *rest = *this;
+ }
+
+ return str;
+}
+
+/// get all characters after the first occurrence of ch
+/// (returns empty string if ch not found)
+wxString wxString::AfterFirst(wxUniChar ch) const
+{
+ wxString str;
+ int iPos = Find(ch);
+ if ( iPos != wxNOT_FOUND )
+ str.assign(*this, iPos + 1, npos);
+
+ return str;
+}
+
+// replace first (or all) occurrences of some substring with another one
+size_t wxString::Replace(const wxString& strOld,
+ const wxString& strNew, bool bReplaceAll)
+{
+ // if we tried to replace an empty string we'd enter an infinite loop below
+ wxCHECK_MSG( !strOld.empty(), 0,
+ wxT("wxString::Replace(): invalid parameter") );
+
+ wxSTRING_INVALIDATE_CACHE();
+
+ size_t uiCount = 0; // count of replacements made
+
+ // optimize the special common case: replacement of one character by
+ // another one (in UTF-8 case we can only do this for ASCII characters)
+ //
+ // benchmarks show that this special version is around 3 times faster
+ // (depending on the proportion of matching characters and UTF-8/wchar_t
+ // build)
+ if ( strOld.m_impl.length() == 1 && strNew.m_impl.length() == 1 )
+ {
+ const wxStringCharType chOld = strOld.m_impl[0],
+ chNew = strNew.m_impl[0];
+
+ // this loop is the simplified version of the one below
+ for ( size_t pos = 0; ; )
+ {
+ pos = m_impl.find(chOld, pos);
+ if ( pos == npos )
+ break;
+
+ m_impl[pos++] = chNew;
+
+ uiCount++;
+
+ if ( !bReplaceAll )
+ break;
+ }
+ }
+ else if ( !bReplaceAll)
+ {
+ size_t pos = m_impl.find(strOld.m_impl, 0);
+ if ( pos != npos )
+ {
+ m_impl.replace(pos, strOld.m_impl.length(), strNew.m_impl);
+ uiCount = 1;
+ }
+ }
+ else // replace all occurrences
+ {
+ const size_t uiOldLen = strOld.m_impl.length();
+ const size_t uiNewLen = strNew.m_impl.length();
+
+ // first scan the string to find all positions at which the replacement
+ // should be made
+ wxVector<size_t> replacePositions;
+
+ size_t pos;
+ for ( pos = m_impl.find(strOld.m_impl, 0);
+ pos != npos;
+ pos = m_impl.find(strOld.m_impl, pos + uiOldLen))
+ {
+ replacePositions.push_back(pos);
+ ++uiCount;
+ }
+
+ if ( !uiCount )
+ return 0;
+
+ // allocate enough memory for the whole new string
+ wxString tmp;
+ tmp.m_impl.reserve(m_impl.length() + uiCount*(uiNewLen - uiOldLen));
+
+ // copy this string to tmp doing replacements on the fly
+ size_t replNum = 0;
+ for ( pos = 0; replNum < uiCount; replNum++ )
+ {
+ const size_t nextReplPos = replacePositions[replNum];
+
+ if ( pos != nextReplPos )
+ {
+ tmp.m_impl.append(m_impl, pos, nextReplPos - pos);
+ }
+
+ tmp.m_impl.append(strNew.m_impl);
+ pos = nextReplPos + uiOldLen;
+ }
+
+ if ( pos != m_impl.length() )
+ {
+ // append the rest of the string unchanged
+ tmp.m_impl.append(m_impl, pos, m_impl.length() - pos);
+ }
+
+ swap(tmp);
+ }
+
+ return uiCount;
+}
+
+bool wxString::IsAscii() const
+{
+ for ( const_iterator i = begin(); i != end(); ++i )
+ {
+ if ( !(*i).IsAscii() )
+ return false;
+ }
+
+ return true;
+}
+
+bool wxString::IsWord() const
+{
+ for ( const_iterator i = begin(); i != end(); ++i )
+ {
+ if ( !wxIsalpha(*i) )
+ return false;
+ }
+
+ return true;
+}
+
+bool wxString::IsNumber() const
+{
+ if ( empty() )
+ return true;
+
+ const_iterator i = begin();
+
+ if ( *i == wxT('-') || *i == wxT('+') )
+ ++i;
+
+ for ( ; i != end(); ++i )
+ {
+ if ( !wxIsdigit(*i) )
+ return false;
+ }
+
+ return true;
+}
+
+wxString wxString::Strip(stripType w) const
+{
+ wxString s = *this;
+ if ( w & leading ) s.Trim(false);
+ if ( w & trailing ) s.Trim(true);
+ return s;
+}
+
+// ---------------------------------------------------------------------------
+// case conversion
+// ---------------------------------------------------------------------------
+
+wxString& wxString::MakeUpper()
+{
+ for ( iterator it = begin(), en = end(); it != en; ++it )
+ *it = (wxChar)wxToupper(*it);
+
+ return *this;
+}
+
+wxString& wxString::MakeLower()
+{
+ for ( iterator it = begin(), en = end(); it != en; ++it )
+ *it = (wxChar)wxTolower(*it);
+
+ return *this;
+}
+
+wxString& wxString::MakeCapitalized()
+{
+ const iterator en = end();
+ iterator it = begin();
+ if ( it != en )
+ {
+ *it = (wxChar)wxToupper(*it);
+ for ( ++it; it != en; ++it )
+ *it = (wxChar)wxTolower(*it);
+ }
+
+ return *this;
+}
+
+// ---------------------------------------------------------------------------
+// trimming and padding
+// ---------------------------------------------------------------------------
+
+// some compilers (VC++ 6.0 not to name them) return true for a call to
+// isspace('\xEA') in the C locale which seems to be broken to me, but we have
+// to live with this by checking that the character is a 7 bit one - even if
+// this may fail to detect some spaces (I don't know if Unicode doesn't have
+// space-like symbols somewhere except in the first 128 chars), it is arguably
+// still better than trimming away accented letters
+inline int wxSafeIsspace(wxChar ch) { return (ch < 127) && wxIsspace(ch); }
+
+// trims spaces (in the sense of isspace) from left or right side
+wxString& wxString::Trim(bool bFromRight)
+{
+ // first check if we're going to modify the string at all
+ if ( !empty() &&
+ (
+ (bFromRight && wxSafeIsspace(GetChar(length() - 1))) ||
+ (!bFromRight && wxSafeIsspace(GetChar(0u)))
+ )
+ )
+ {
+ if ( bFromRight )
+ {
+ // find last non-space character
+ reverse_iterator psz = rbegin();
+ while ( (psz != rend()) && wxSafeIsspace(*psz) )
+ ++psz;
+
+ // truncate at trailing space start
+ erase(psz.base(), end());
+ }
+ else
+ {
+ // find first non-space character
+ iterator psz = begin();
+ while ( (psz != end()) && wxSafeIsspace(*psz) )
+ ++psz;
+
+ // fix up data and length
+ erase(begin(), psz);
+ }
+ }
+
+ return *this;
+}
+
+// adds nCount characters chPad to the string from either side
+wxString& wxString::Pad(size_t nCount, wxUniChar chPad, bool bFromRight)
+{
+ wxString s(chPad, nCount);
+
+ if ( bFromRight )
+ *this += s;
+ else
+ {
+ s += *this;
+ swap(s);
+ }
+
+ return *this;
+}
+
+// truncate the string
+wxString& wxString::Truncate(size_t uiLen)
+{
+ if ( uiLen < length() )
+ {
+ erase(begin() + uiLen, end());
+ }
+ //else: nothing to do, string is already short enough
+
+ return *this;
+}
+
+// ---------------------------------------------------------------------------
+// finding (return wxNOT_FOUND if not found and index otherwise)
+// ---------------------------------------------------------------------------
+
+// find a character
+int wxString::Find(wxUniChar ch, bool bFromEnd) const
+{
+ size_type idx = bFromEnd ? find_last_of(ch) : find_first_of(ch);
+
+ return (idx == npos) ? wxNOT_FOUND : (int)idx;
+}
+
+// ----------------------------------------------------------------------------
+// conversion to numbers
+// ----------------------------------------------------------------------------
+
+// The implementation of all the functions below is exactly the same so factor
+// it out. Note that number extraction works correctly on UTF-8 strings, so
+// we can use wxStringCharType and wx_str() for maximum efficiency.
+
+#ifndef __WXWINCE__
+ #define DO_IF_NOT_WINCE(x) x
+#else
+ #define DO_IF_NOT_WINCE(x)
+#endif
+
+#define WX_STRING_TO_X_TYPE_START \
+ wxCHECK_MSG( pVal, false, wxT("NULL output pointer") ); \
+ DO_IF_NOT_WINCE( errno = 0; ) \
+ const wxStringCharType *start = wx_str(); \
+ wxStringCharType *end;
+
+// notice that we return false without modifying the output parameter at all if
+// nothing could be parsed but we do modify it and return false then if we did
+// parse something successfully but not the entire string
+#define WX_STRING_TO_X_TYPE_END \
+ if ( end == start DO_IF_NOT_WINCE(|| errno == ERANGE) ) \
+ return false; \
+ *pVal = val; \
+ return !*end;
+
+bool wxString::ToLong(long *pVal, int base) const
+{
+ wxASSERT_MSG( !base || (base > 1 && base <= 36), wxT("invalid base") );
+
+ WX_STRING_TO_X_TYPE_START
+ long val = wxStrtol(start, &end, base);
+ WX_STRING_TO_X_TYPE_END
+}
+
+bool wxString::ToULong(unsigned long *pVal, int base) const
+{
+ wxASSERT_MSG( !base || (base > 1 && base <= 36), wxT("invalid base") );
+
+ WX_STRING_TO_X_TYPE_START
+ unsigned long val = wxStrtoul(start, &end, base);
+ WX_STRING_TO_X_TYPE_END
+}
+
+bool wxString::ToLongLong(wxLongLong_t *pVal, int base) const
+{
+ wxASSERT_MSG( !base || (base > 1 && base <= 36), wxT("invalid base") );
+
+ WX_STRING_TO_X_TYPE_START
+ wxLongLong_t val = wxStrtoll(start, &end, base);
+ WX_STRING_TO_X_TYPE_END
+}
+
+bool wxString::ToULongLong(wxULongLong_t *pVal, int base) const
+{
+ wxASSERT_MSG( !base || (base > 1 && base <= 36), wxT("invalid base") );
+
+ WX_STRING_TO_X_TYPE_START
+ wxULongLong_t val = wxStrtoull(start, &end, base);
+ WX_STRING_TO_X_TYPE_END
+}