From e21011866e9a89b5abda727f80e666ed2d7041c7 Mon Sep 17 00:00:00 2001 From: Mattia Barbon Date: Mon, 1 Sep 2003 20:20:21 +0000 Subject: [PATCH] Corrected statements about wxString correctly handling embedded '\0' characters. Fixed various wxString::*find* methods (patch by Robert Vazan), plus added missing overloaded variants of find_first/last_(not_)of. Added more tests in console sample. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@23357 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/latex/wx/tstring.tex | 5 +- docs/latex/wx/wxstring.tex | 2 +- include/wx/string.h | 6 +- samples/console/console.cpp | 149 +++++++++++++++++++++++++++++++++++- src/common/string.cpp | 85 +++++++++++++++----- 5 files changed, 222 insertions(+), 25 deletions(-) diff --git a/docs/latex/wx/tstring.tex b/docs/latex/wx/tstring.tex index dce111c7cb..7449e617e2 100644 --- a/docs/latex/wx/tstring.tex +++ b/docs/latex/wx/tstring.tex @@ -6,8 +6,9 @@ Classes: \helpref{wxString}{wxstring}, \helpref{wxArrayString}{wxarraystring}, \ wxString is a class which represents a character string of arbitrary length (limited by {\it MAX\_INT} which is usually 2147483647 on 32 bit machines) and containing -arbitrary characters. The ASCII NUL character is allowed, although care should be -taken when passing strings containing it to other functions. +arbitrary characters. The ASCII NUL character is allowed, but be aware that +in the current string implementation some methods might not work correctly +in this case. wxString works with both ASCII (traditional, 7 or 8 bit, characters) as well as Unicode (wide characters) strings. diff --git a/docs/latex/wx/wxstring.tex b/docs/latex/wx/wxstring.tex index b81b116412..9f242d2240 100644 --- a/docs/latex/wx/wxstring.tex +++ b/docs/latex/wx/wxstring.tex @@ -6,7 +6,7 @@ there, wxString implements about 90\% of methods of the std::string class (itera are not supported, nor all methods which use them). These standard functions are not documented in this manual so please see the STL documentation. The behaviour of all these functions is identical to the behaviour described -there. +there (except that wxString is sensitive to null character). You may notice that wxString sometimes has many functions which do the same thing like, for example, \helpref{Length()}{wxstringlength}, diff --git a/include/wx/string.h b/include/wx/string.h index d402585c46..ee362ff90c 100644 --- a/include/wx/string.h +++ b/include/wx/string.h @@ -523,6 +523,7 @@ public: { return find_first_of(str.c_str(), nStart); } // same as above size_t find_first_of(const wxChar* sz, size_t nStart = 0) const; + size_t find_first_of(const wxChar* sz, size_t nStart, size_t n) const; // same as find(char, size_t) size_t find_first_of(wxChar c, size_t nStart = 0) const { return find(c, nStart); } @@ -531,6 +532,7 @@ public: { return find_last_of(str.c_str(), nStart); } // same as above size_t find_last_of (const wxChar* sz, size_t nStart = npos) const; + size_t find_last_of(const wxChar* sz, size_t nStart, size_t n) const; // same as above size_t find_last_of(wxChar c, size_t nStart = npos) const { return rfind(c, nStart); } @@ -542,13 +544,15 @@ public: { return find_first_not_of(str.c_str(), nStart); } // same as above size_t find_first_not_of(const wxChar* sz, size_t nStart = 0) const; + size_t find_first_not_of(const wxChar* sz, size_t nStart, size_t n) const; // same as above size_t find_first_not_of(wxChar ch, size_t nStart = 0) const; // as strcspn() size_t find_last_not_of(const wxStringBase& str, size_t nStart = npos) const - { return find_first_not_of(str.c_str(), nStart); } + { return find_last_not_of(str.c_str(), nStart); } // same as above size_t find_last_not_of(const wxChar* sz, size_t nStart = npos) const; + size_t find_last_not_of(const wxChar* sz, size_t nStart, size_t n) const; // same as above size_t find_last_not_of(wxChar ch, size_t nStart = npos) const; diff --git a/samples/console/console.cpp b/samples/console/console.cpp index 417daefcd4..4f7d0d4519 100644 --- a/samples/console/console.cpp +++ b/samples/console/console.cpp @@ -97,7 +97,7 @@ #undef TEST_ALL static const bool TEST_ALL = true; #else - #define TEST_HASHSET + #define TEST_STRINGS static const bool TEST_ALL = false; #endif @@ -6551,6 +6551,20 @@ void is(int line, const wxString& got, const wxString& expected, } } +#if 0 +void is(int line, const wxChar* got, const wxChar* expected, + const wxString& msg = wxEmptyString) +{ + bool isOk = wxStrcmp( got, expected ) == 0; + ok(line, isOk, msg); + if( !isOk ) + { + wxPuts(_T("Got: ") + wxString(got)); + wxPuts(_T("Expected: ") + wxString(expected)); + } +} +#endif + void is(int line, const wxChar& got, const wxChar& expected, const wxString& msg = wxEmptyString) { @@ -6558,11 +6572,26 @@ void is(int line, const wxChar& got, const wxChar& expected, ok(line, isOk, msg); if( !isOk ) { - wxPuts("Got: " + got); - wxPuts("Expected: " + expected); + wxPuts(_T("Got: ") + got); + wxPuts(_T("Expected: ") + expected); + } +} + +void is(int line, size_t got, size_t expected, + const wxString& msg = wxEmptyString) +{ + bool isOk = got == expected; + ok(line, isOk, msg); + if( !isOk ) + { + wxPuts(wxString::Format(_T("Got: %ld"), got)); + wxPuts(wxString::Format(_T("Expected: %ld"), expected)); } } +#define is_m( got, expected, message ) is( __LINE__, (got), (expected), (message) ) +#define is_nom( got, expected ) is( __LINE__, (got), (expected), wxEmptyString ) + void TestStdString() { wxPuts(_T("*** Testing std::string operations ***\n")); @@ -6652,6 +6681,77 @@ void TestStdString() is( __LINE__, *it2, _T('g') ); ok( __LINE__, it3 == s7.end() ); + // find + // 0 1 2 + // 01234567890123456789012345 + s1 = _T("abcdefgABCDEFGabcABCabcABC"); + s2 = _T("gAB"); + + is_nom( s1.find(_T('A')), 7u ); + is_nom( s1.find(_T('A'), 7), 7u ); + is_nom( s1.find(_T('Z')), wxString::npos ); + is_nom( s1.find(_T('C'), 22), 25u ); + + is_nom( s1.find(_T("gAB")), 6u ); + is_nom( s1.find(_T("gAB"), 7), wxString::npos ); + is_nom( s1.find(_T("gAB"), 6), 6u ); + + is_nom( s1.find(_T("gABZZZ"), 2, 3), 6u ); + is_nom( s1.find(_T("gABZZZ"), 7, 3), wxString::npos ); + + is_nom( s1.find(s2), 6u ); + is_nom( s1.find(s2, 7), wxString::npos ); + is_nom( s1.find(s2, 6), 6u ); + + // find_first_not_of + // 0 1 2 3 + // 01234567890123456789012345678901234 + s1 = _T("aaaaaabcdefghlkjiaaaaaabcdbcdbcdbcd"); + s2 = _T("aaaaaa"); + + is_nom( s1.find_first_not_of(_T('a')), 6u ); + is_nom( s1.find_first_not_of(_T('a'), 7), 7u ); + is_nom( s2.find_first_not_of(_T('a')), wxString::npos ); + + is_nom( s1.find_first_not_of(_T("abde"), 4), 7u ); + is_nom( s1.find_first_not_of(_T("abde"), 7), 7u ); + is_nom( s1.find_first_not_of(_T("abcdefghijkl")), wxString::npos ); + + is_nom( s1.find_first_not_of(_T("abcdefghi"), 0, 4), 9u ); + + // find_first_of + is_nom( s1.find_first_of(_T('c')), 7u ); + is_nom( s1.find_first_of(_T('v')), wxString::npos ); + is_nom( s1.find_first_of(_T('c'), 10), 24u ); + + is_nom( s1.find_first_of(_T("ijkl")), 13u ); + is_nom( s1.find_first_of(_T("ddcfg"), 17), 24u ); + is_nom( s1.find_first_of(_T("ddcfga"), 17, 5), 24u ); + + // find_last_not_of + // 0 1 2 3 + // 01234567890123456789012345678901234 + s1 = _T("aaaaaabcdefghlkjiaaaaaabcdbcdbcdbcd"); + s2 = _T("aaaaaa"); + + is_nom( s2.find_last_not_of(_T('a')), wxString::npos ); + is_nom( s1.find_last_not_of(_T('d')), 33u ); + is_nom( s1.find_last_not_of(_T('d'), 25), 24u ); + + is_nom( s1.find_last_not_of(_T("bcd")), 22u ); + is_nom( s1.find_last_not_of(_T("abc"), 24), 16u ); + + is_nom( s1.find_last_not_of(_T("abcdefghijklmnopqrstuv"), 24, 3), 16u ); + + // find_last_of + is_nom( s2.find_last_of(_T('c')), wxString::npos ); + is_nom( s1.find_last_of(_T('a')), 22u ); + is_nom( s1.find_last_of(_T('b'), 24), 23u ); + + is_nom( s1.find_last_of(_T("ijklm")), 16u ); + is_nom( s1.find_last_of(_T("ijklma"), 33, 4), 16u ); + is_nom( s1.find_last_of(_T("a"), 17), 17u ); + // test insert s1 = s2 = s3 = s4 = s5 = s6 = s7 = s8 = _T("aaaa"); s9 = s10 = _T("cdefg"); @@ -6702,6 +6802,49 @@ void TestStdString() is( __LINE__, s6, s9); is( __LINE__, s7, _T("QWwertyP") ); + // rfind + // 0 1 2 + // 01234567890123456789012345 + s1 = _T("abcdefgABCDEFGabcABCabcABC"); + s2 = _T("gAB"); + + is_nom( s1.rfind(_T('A')), 23u ); + is_nom( s1.rfind(_T('A'), 7), 7u ); + is_nom( s1.rfind(_T('Z')), wxString::npos ); + is_nom( s1.rfind(_T('C'), 22), 19u ); + + is_nom( s1.rfind(_T("cAB")), 22u ); + is_nom( s1.rfind(_T("cAB"), 15), wxString::npos ); + is_nom( s1.rfind(_T("cAB"), 21), 16u ); + + is_nom( s1.rfind(_T("gABZZZ"), 7, 3), 6u ); + is_nom( s1.rfind(_T("gABZZZ"), 5, 3), wxString::npos ); + + is_nom( s1.rfind(s2), 6u ); + is_nom( s1.rfind(s2, 5), wxString::npos ); + is_nom( s1.rfind(s2, 6), 6u ); + + // resize + s1 = s2 = s3 = s4 = _T("abcABCdefDEF"); + + s1.resize( 12 ); + s2.resize( 10 ); + s3.resize( 14, _T(' ') ); + s4.resize( 14, _T('W') ); + + is_nom( s1, _T("abcABCdefDEF") ); + is_nom( s2, _T("abcABCdefD") ); + is_nom( s3, _T("abcABCdefDEF ") ); + is_nom( s4, _T("abcABCdefDEFWW") ); + + // substr + s1 = _T("abcdefgABCDEFG"); + + is_nom( s1.substr( 0, 14 ), s1 ); + is_nom( s1.substr( 1, 13 ), _T("bcdefgABCDEFG") ); + is_nom( s1.substr( 1, 20 ), _T("bcdefgABCDEFG") ); + is_nom( s1.substr( 14, 30 ), _T("") ); + wxPuts(_T("*** Testing std::string operations finished ***\n")); } diff --git a/src/common/string.cpp b/src/common/string.cpp index 4715f63154..76a89a88a3 100644 --- a/src/common/string.cpp +++ b/src/common/string.cpp @@ -479,18 +479,36 @@ size_t wxStringBase::find(wxChar ch, size_t nStart) const size_t wxStringBase::rfind(const wxStringBase& str, size_t nStart) const { - wxASSERT( str.GetStringData()->IsValid() ); - wxASSERT( nStart == npos || nStart <= length() ); - - // TODO could be made much quicker than that - const wxChar *p = c_str() + (nStart == npos ? length() : nStart); - while ( p >= c_str() + str.length() ) { - if ( wxStrncmp(p - str.length(), str.c_str(), str.length()) == 0 ) - return p - str.length() - c_str(); - p--; - } + wxASSERT( str.GetStringData()->IsValid() ); + wxASSERT( nStart == npos || nStart <= length() ); + + if ( length() >= str.length() ) + { + // avoids a corner case later + if ( length() == 0 && str.length() == 0 ) + return 0; + + // "top" is the point where search starts from + size_t top = length() - str.length(); - return npos; + if ( nStart == npos ) + nStart = length() - 1; + if ( nStart < top ) + top = nStart; + + const wxChar *cursor = c_str() + top; + do + { + if ( memcmp(cursor, str.c_str(), + str.length() * sizeof(wxChar)) == 0 ) + { + return cursor - c_str(); + } + --cursor; + } while ( cursor > c_str() ); + } + + return npos; } size_t wxStringBase::rfind(const wxChar* sz, size_t nStart, size_t n) const @@ -530,11 +548,17 @@ size_t wxStringBase::find_first_of(const wxChar* sz, size_t nStart) const return npos; } +size_t wxStringBase::find_first_of(const wxChar* sz, size_t nStart, + size_t n) const +{ + return find_first_of(wxStringBase(sz, n), nStart); +} + size_t wxStringBase::find_last_of(const wxChar* sz, size_t nStart) const { if ( nStart == npos ) { - nStart = length(); + nStart = length() - 1; } else { @@ -542,7 +566,7 @@ size_t wxStringBase::find_last_of(const wxChar* sz, size_t nStart) const _T("invalid index in find_last_of()") ); } - for ( const wxChar *p = c_str() + nStart - 1; p >= c_str(); p-- ) + for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p ) { if ( wxStrchr(sz, *p) ) return p - c_str(); @@ -551,6 +575,12 @@ size_t wxStringBase::find_last_of(const wxChar* sz, size_t nStart) const return npos; } +size_t wxStringBase::find_last_of(const wxChar* sz, size_t nStart, + size_t n) const +{ + return find_last_of(wxStringBase(sz, n), nStart); +} + size_t wxStringBase::find_first_not_of(const wxChar* sz, size_t nStart) const { if ( nStart == npos ) @@ -566,7 +596,13 @@ size_t wxStringBase::find_first_not_of(const wxChar* sz, size_t nStart) const if ( nAccept >= length() - nStart ) return npos; else - return nAccept; + return nStart + nAccept; +} + +size_t wxStringBase::find_first_not_of(const wxChar* sz, size_t nStart, + size_t n) const +{ + return find_first_not_of(wxStringBase(sz, n), nStart); } size_t wxStringBase::find_first_not_of(wxChar ch, size_t nStart) const @@ -586,14 +622,14 @@ size_t wxStringBase::find_last_not_of(const wxChar* sz, size_t nStart) const { if ( nStart == npos ) { - nStart = length(); + nStart = length() - 1; } else { wxASSERT( nStart <= length() ); } - for ( const wxChar *p = c_str() + nStart - 1; p >= c_str(); p-- ) + for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p ) { if ( !wxStrchr(sz, *p) ) return p - c_str(); @@ -602,18 +638,24 @@ size_t wxStringBase::find_last_not_of(const wxChar* sz, size_t nStart) const return npos; } +size_t wxStringBase::find_last_not_of(const wxChar* sz, size_t nStart, + size_t n) const +{ + return find_last_not_of(wxStringBase(sz, n), nStart); +} + size_t wxStringBase::find_last_not_of(wxChar ch, size_t nStart) const { if ( nStart == npos ) { - nStart = length(); + nStart = length() - 1; } else { wxASSERT( nStart <= length() ); } - for ( const wxChar *p = c_str() + nStart - 1; p >= c_str(); p-- ) + for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p ) { if ( *p != ch ) return p - c_str(); @@ -2172,6 +2214,13 @@ void wxArrayString::Remove(const wxChar *sz) RemoveAt(iIndex); } +void wxArrayString::assign(const_iterator first, const_iterator last) +{ + reserve(last - first); + for(; first != last; ++first) + push_back(*first); +} + // ---------------------------------------------------------------------------- // sorting // ---------------------------------------------------------------------------- -- 2.47.2