Search and replace algorithm for string

Discussion in 'C++' started by M, Aug 2, 2005.

  1. M

    M Guest

    Hi,

    I've searched through the previous posts and there seems to be a few
    examples of search and replacing all occurrances of a string with
    another string.

    I would have thought that the code below would work...

    string gsub(const string & sData,
    const string & sFrom,
    const string & sTo)
    {
    string sNew = sData;

    if (! sNew.empty())
    {
    std::replace(sData.begin(), sData.end(),
    sFrom,
    sTo);

    }
    return sNew;
    }

    But, it produces the following compiler error:

    /usr/include/c++/3.2/bits/stl_algo.h: In function `void
    std::replace(_ForwardIter, _ForwardIter, const _Tp&, const _Tp&) [with
    _ForwardIter = __gnu_cxx::__normal_iterator<const char*,
    std::basic_string<char, std::char_traits<char>, std::allocator<char> >
    >, _Tp = std::basic_string<char, std::char_traits<char>,
    >std::allocator<char> >]':

    str_tst.cpp:132: instantiated from here
    /usr/include/c++/3.2/bits/stl_algo.h:809: no match for `const char& ==
    const std::basic_string<char, std::char_traits<char>,
    std::allocator<char> >&' operator
    str_tst.cpp:132: instantiated from here
    /usr/include/c++/3.2/bits/stl_algo.h:810: assignment of read-only
    location
    /usr/include/c++/3.2/bits/stl_algo.h:810: cannot convert `const
    std::basic_string<char, std::char_traits<char>, std::allocator<char> >'
    to `const char' in assignment

    What am I doing wrong here? Looking at the function signature, it should
    work. Cannot see why the attempted conversion.

    Regards,

    Michael
    M, Aug 2, 2005
    #1
    1. Advertising

  2. "M" <> wrote in message
    news:TDyHe.69154$...

    > I would have thought that the code below would work...
    >
    > string gsub(const string & sData,
    > const string & sFrom,
    > const string & sTo)
    > {
    > string sNew = sData;
    >
    > if (! sNew.empty())
    > {
    > std::replace(sData.begin(), sData.end(),
    > sFrom,
    > sTo);
    >
    > }
    > return sNew;
    > }


    Not unless you change the call to std::replace to use sNew instead of sData.
    Andrew Koenig, Aug 2, 2005
    #2
    1. Advertising

  3. M

    Guest

    Andrew Koenig wrote:
    > "M" <> wrote in message
    > news:TDyHe.69154$...

    <SNIP>
    > Not unless you change the call to std::replace to use sNew instead of sData.


    Hi Andrew,

    No go, I still the same problem (sorry about the above though, just
    changed some of the variable names).

    Here is the test code:

    #include <iostream>
    #include <algorithm>
    #include <string>

    using namespace std;

    string gsub(const string & sData,
    const string & sFrom,
    const string & sTo)
    {
    string sNew = sData;
    if (! sNew.empty())
    {
    std::replace(sNew.begin(), sNew.end(),
    sFrom,
    sTo);
    }
    return sNew;
    }


    int main(void)
    {
    const string sData = "Some text";
    string sFrom = "text";
    string sTo = "information";

    cout << "Original text: "
    << sData
    << "\n"
    << "After search and replace: "
    << gsub(sData, sFrom, sTo)
    << endl;

    return 0;
    }


    The above compiler error was produced on linux, the following error on
    aix

    "/usr/.../include/algorithm", line 243.25: 1540-0218 (S) The call does
    not match any parameter list for "operator==".
    "/usr/.../include/utility", line 77.14: 1540-1283 (I) "template <class
    _T1, class _T2> std::eek:perator==(const pair<_T1,_T2> &, const
    pair<_T1,_T2> &)" is not a viable candidate.
    "/usr/.../include/xutility", line 384.14: 1540-1283 (I) "template
    <class _RI> std::eek:perator==(const reverse_iterator<_RI> &, const
    reverse_iterator<_RI> &)" is not a viable candidate.
    "/usr/.../include/xutility", line 499.14: 1540-1283 (I) "template
    <class _E, class _Tr> std::eek:perator==(const istreambuf_iterator<_E,_Tr>
    &, const istreambuf_iterator<_E,_Tr> &)" is not a viable candidate.
    "/usr/.../include/xmemory", line 155.14: 1540-1283 (I) "template <class
    _Ty, class _U> std::eek:perator==(const allocator<_Ty> &, const
    allocator<_U> &)" is not a viable candidate.
    "/usr/.../include/string", line 101.14: 1540-1283 (I) "template <class
    _E, class _Tr, class _A> std::eek:perator==(const basic_string<_E,_Tr,_A>
    &, const basic_string<_E,_Tr,_A> &)" is not a viable candidate.
    "/usr/.../include/string", line 105.14: 1540-1283 (I) "template <class
    _E, class _Tr, class _A> std::eek:perator==(const _E *, const
    basic_string<_E,_Tr,_A> &)" is not a viable candidate.
    "/usr/.../include/string", line 109.14: 1540-1283 (I) "template <class
    _E, class _Tr, class _A> std::eek:perator==(const basic_string<_E,_Tr,_A>
    &, const _E *)" is not a viable candidate.
    "/usr/.../include/iterator", line 184.14: 1540-1283 (I) "template
    <class _Ty, class _E, class _Tr, class _Dist> std::eek:perator==(const
    istream_iterator<_Ty,_E,_Tr,_Dist> &, const
    istream_iterator<_Ty,_E,_Tr,_Dist> &)" is not a viable candidate.
    "/usr/.../include/algorithm", line 241.14: 1540-0700 (I) The previous
    message was produced while processing
    "std::replace<std::_Ptrit<char,long,char *,char &,char *,char
    &>,std::basic_string<char,std::char_traits<char>,std::allocator<char> >
    >(_Ptrit<char,long,char *,char &,char *,char &>, _Ptrit<char,long,char *,char &,char *,char &>, const basic_string<char,std::char_traits<char>,std::allocator<char> > &, const basic_string<char,std::char_traits<char>,std::allocator<char> > &)".

    "strtst.cpp", line 19.9: 1540-0700 (I) The previous message was
    produced while processing "gsub(const string &, const string &, const
    string &)".
    "/usr/.../include/algorithm", line 244.29: 1540-0218 (S) The call does
    not match any parameter list for "operator=".
    "/usr/.../include/algorithm", line 244.29: 1540-1283 (I) "builtin
    operator=(char, char)" is not a viable candidate.

    Regards,

    Michael
    , Aug 2, 2005
    #3
  4. wrote:
    > Andrew Koenig wrote:
    >>"M" <> wrote in message
    >>news:TDyHe.69154$...

    > <SNIP>
    >>Not unless you change the call to std::replace to use sNew instead of sData.

    >
    > Hi Andrew,
    >
    > No go, I still the same problem (sorry about the above though, just
    > changed some of the variable names).
    >
    > Here is the test code:
    >
    > #include <iostream>
    > #include <algorithm>
    > #include <string>
    >
    > using namespace std;
    >
    > string gsub(const string & sData,
    > const string & sFrom,
    > const string & sTo)
    > {
    > string sNew = sData;
    > if (! sNew.empty())
    > {
    > std::replace(sNew.begin(), sNew.end(),
    > sFrom,
    > sTo);
    > }
    > return sNew;
    > }
    >
    >
    > int main(void)
    > {
    > const string sData = "Some text";
    > string sFrom = "text";
    > string sTo = "information";
    >
    > cout << "Original text: "
    > << sData
    > << "\n"
    > << "After search and replace: "
    > << gsub(sData, sFrom, sTo)
    > << endl;
    >
    > return 0;
    > }
    >
    >
    > The above compiler error was produced on linux, the following error on
    > aix
    >
    > "/usr/.../include/algorithm", line 243.25: 1540-0218 (S) The call does
    > not match any parameter list for "operator==".
    > "/usr/.../include/utility", line 77.14: 1540-1283 (I) "template <class
    > _T1, class _T2> std::eek:perator==(const pair<_T1,_T2> &, const
    > pair<_T1,_T2> &)" is not a viable candidate.
    > "/usr/.../include/xutility", line 384.14: 1540-1283 (I) "template
    > <class _RI> std::eek:perator==(const reverse_iterator<_RI> &, const
    > reverse_iterator<_RI> &)" is not a viable candidate.
    > "/usr/.../include/xutility", line 499.14: 1540-1283 (I) "template
    > <class _E, class _Tr> std::eek:perator==(const istreambuf_iterator<_E,_Tr>
    > &, const istreambuf_iterator<_E,_Tr> &)" is not a viable candidate.
    > "/usr/.../include/xmemory", line 155.14: 1540-1283 (I) "template <class
    > _Ty, class _U> std::eek:perator==(const allocator<_Ty> &, const
    > allocator<_U> &)" is not a viable candidate.
    > "/usr/.../include/string", line 101.14: 1540-1283 (I) "template <class
    > _E, class _Tr, class _A> std::eek:perator==(const basic_string<_E,_Tr,_A>
    > &, const basic_string<_E,_Tr,_A> &)" is not a viable candidate.
    > "/usr/.../include/string", line 105.14: 1540-1283 (I) "template <class
    > _E, class _Tr, class _A> std::eek:perator==(const _E *, const
    > basic_string<_E,_Tr,_A> &)" is not a viable candidate.
    > "/usr/.../include/string", line 109.14: 1540-1283 (I) "template <class
    > _E, class _Tr, class _A> std::eek:perator==(const basic_string<_E,_Tr,_A>
    > &, const _E *)" is not a viable candidate.
    > "/usr/.../include/iterator", line 184.14: 1540-1283 (I) "template
    > <class _Ty, class _E, class _Tr, class _Dist> std::eek:perator==(const
    > istream_iterator<_Ty,_E,_Tr,_Dist> &, const
    > istream_iterator<_Ty,_E,_Tr,_Dist> &)" is not a viable candidate.
    > "/usr/.../include/algorithm", line 241.14: 1540-0700 (I) The previous
    > message was produced while processing
    > "std::replace<std::_Ptrit<char,long,char *,char &,char *,char
    > &>,std::basic_string<char,std::char_traits<char>,std::allocator<char> >
    >>(_Ptrit<char,long,char *,char &,char *,char &>, _Ptrit<char,long,char *,char &,char *,char &>, const basic_string<char,std::char_traits<char>,std::allocator<char> > &, const basic_string<char,std::char_traits<char>,std::allocator<char> > &)".

    > "strtst.cpp", line 19.9: 1540-0700 (I) The previous message was
    > produced while processing "gsub(const string &, const string &, const
    > string &)".
    > "/usr/.../include/algorithm", line 244.29: 1540-0218 (S) The call does
    > not match any parameter list for "operator=".
    > "/usr/.../include/algorithm", line 244.29: 1540-1283 (I) "builtin
    > operator=(char, char)" is not a viable candidate.
    >
    > Regards,
    >
    > Michael
    >


    If I'm not mistaken, replace will replace all occurences of a char
    with another char (e.g. change all 'a' to 'b'), but does not replace
    multi-char substrings.

    Larry
    Larry I Smith, Aug 2, 2005
    #4
  5. M

    Kelly Walker Guest

    "M" <> wrote in message
    news:TDyHe.69154$...
    > Hi,
    >
    > I've searched through the previous posts and there seems to be a few
    > examples of search and replacing all occurrances of a string with
    > another string.
    >
    > I would have thought that the code below would work...
    >
    > string gsub(const string & sData,
    > const string & sFrom,
    > const string & sTo)
    > {
    > string sNew = sData;
    >
    > if (! sNew.empty())
    > {
    > std::replace(sData.begin(), sData.end(),
    > sFrom,
    > sTo);
    >
    > }
    > return sNew;
    > }
    >


    This is not the main issue, but you cannot call replace on sData because it
    is const. I am sure you mean sNew. Why not pass the string by value in the
    first place:

    string gsub(string sNew,
    const string & sFrom,
    const string & sTo) { ... }

    You gain nothing by passing it be reference if you just copy it.

    > What am I doing wrong here? Looking at the function signature, it should
    > work. Cannot see why the attempted conversion.
    >
    > Regards,
    >
    > Michael


    The problem is that std::string's iterators refer to individual characters
    in the string, NOT substrings. So, you cannot replace a substring with
    another string using iterators and std::replace. You can replace characters
    as in:

    std::string str("aaaaa");
    std::replace(str.begin(), str.end(), 'a', 'b');
    // str is now "bbbbb"

    If you want to replace substrings, you will have to do something more
    complicated like:

    string gsub(const string &sData,
    const string &sFrom,
    const string &sTo) {

    string sNew;
    size_t i = 0;
    while(i < sData.size()) {
    if(sData.substr(i, sFrom.size()) == sFrom) {
    sNew += sTo;
    i += sFrom.size();
    }
    else {
    sNew += sData;
    ++i;
    }
    }
    return sNew;
    }

    This is probably not the most efficient way to do what you want, but you get
    the idea.

    -Kelly
    Kelly Walker, Aug 2, 2005
    #5
  6. M

    Guest

    Hi Larry,

    It looks like your correct, looking at the error message. But when
    looking at the function signature

    void replace(_FI _F, _FI _L, const _Ty& _Vo, const _Ty& _Vn) { ... }

    it's easy to mistake as _Ty is misleading (should have probably been _E
    or something else). The code for the above version of replace, iterates
    over each element and replaces it with the new if it encounters the
    old.

    If this is correct, then I'll apply one of the solutions I've found
    during the search I made on this group. Thanks for your help.

    Regards,

    Michael
    , Aug 2, 2005
    #6
  7. wrote:
    > Andrew Koenig wrote:
    >> "M" <> wrote in message
    >> news:TDyHe.69154$...

    > <SNIP>
    >> Not unless you change the call to std::replace to use sNew instead
    >> of sData.

    >
    > Hi Andrew,
    >
    > No go, I still the same problem (sorry about the above though, just
    > changed some of the variable names).
    > [..]


    I think Andrew is mistaken (as is Michael). std::replace cannot be used
    to replace a substring within a string with another substring. You need
    to use 'std::string::replace' (a member function) for that. RTFM please.

    V
    Victor Bazarov, Aug 2, 2005
    #7
  8. wrote:
    > Hi Larry,
    >
    > It looks like your correct, looking at the error message. But when
    > looking at the function signature
    >
    > void replace(_FI _F, _FI _L, const _Ty& _Vo, const _Ty& _Vn) { ... }
    >
    > it's easy to mistake as _Ty is misleading (should have probably been _E
    > or something else). The code for the above version of replace, iterates
    > over each element and replaces it with the new if it encounters the
    > old.
    >
    > If this is correct, then I'll apply one of the solutions I've found
    > during the search I made on this group. Thanks for your help.
    >
    > Regards,
    >
    > Michael
    >


    Here's one possible solution:

    string gsub(const string& sData,
    const string& sFrom,
    const string& sTo)
    {
    string sNew = sData;

    if (! sNew.empty())
    {
    string::size_type loc;

    while (string::npos != (loc = sNew.find(sFrom)))
    sNew.replace(loc, sFrom.length(), sTo);
    }

    return sNew;
    }

    Regards,
    Larry
    Larry I Smith, Aug 2, 2005
    #8
  9. M

    Guest

    Victor,

    string::replace won't do it either, so you RTFM please.

    Regards,

    Michael
    , Aug 2, 2005
    #9
  10. M

    Kelly Walker Guest

    "Kelly Walker" <> wrote in message
    news:64BHe.1725$...
    > "M" <> wrote in message
    > news:TDyHe.69154$...
    >> Hi,
    >>
    >> I've searched through the previous posts and there seems to be a few
    >> examples of search and replacing all occurrances of a string with
    >> another string.
    >>
    >> I would have thought that the code below would work...
    >>
    >> string gsub(const string & sData,
    >> const string & sFrom,
    >> const string & sTo)
    >> {
    >> string sNew = sData;
    >>
    >> if (! sNew.empty())
    >> {
    >> std::replace(sData.begin(), sData.end(),
    >> sFrom,
    >> sTo);
    >>
    >> }
    >> return sNew;
    >> }
    >>

    >
    > This is not the main issue, but you cannot call replace on sData because
    > it is const. I am sure you mean sNew. Why not pass the string by value
    > in the first place:
    >
    > string gsub(string sNew,
    > const string & sFrom,
    > const string & sTo) { ... }
    >
    > You gain nothing by passing it be reference if you just copy it.
    >
    >> What am I doing wrong here? Looking at the function signature, it should
    >> work. Cannot see why the attempted conversion.
    >>
    >> Regards,
    >>
    >> Michael

    >
    > The problem is that std::string's iterators refer to individual characters
    > in the string, NOT substrings. So, you cannot replace a substring with
    > another string using iterators and std::replace. You can replace
    > characters as in:
    >
    > std::string str("aaaaa");
    > std::replace(str.begin(), str.end(), 'a', 'b');
    > // str is now "bbbbb"
    >
    > If you want to replace substrings, you will have to do something more
    > complicated like:
    >
    > string gsub(const string &sData,
    > const string &sFrom,
    > const string &sTo) {
    >
    > string sNew;
    > size_t i = 0;
    > while(i < sData.size()) {
    > if(sData.substr(i, sFrom.size()) == sFrom) {
    > sNew += sTo;
    > i += sFrom.size();
    > }
    > else {
    > sNew += sData;
    > ++i;
    > }
    > }
    > return sNew;
    > }
    >
    > This is probably not the most efficient way to do what you want, but you
    > get the idea.
    >
    > -Kelly
    >


    Oops - I forgot about string::replace()...
    Kelly Walker, Aug 2, 2005
    #10
  11. M

    Guest

    Victor,

    Relax man, no need to get in a state about something so trivial.
    std::string::replace won't do it either. Maybe take your own advise...

    Regards,

    Michael
    , Aug 2, 2005
    #11
  12. Larry I Smith wrote:
    > wrote:
    >>Hi Larry,
    >>
    >>It looks like your correct, looking at the error message. But when
    >>looking at the function signature
    >>
    >>void replace(_FI _F, _FI _L, const _Ty& _Vo, const _Ty& _Vn) { ... }
    >>
    >>it's easy to mistake as _Ty is misleading (should have probably been _E
    >>or something else). The code for the above version of replace, iterates
    >>over each element and replaces it with the new if it encounters the
    >>old.
    >>
    >>If this is correct, then I'll apply one of the solutions I've found
    >>during the search I made on this group. Thanks for your help.
    >>
    >>Regards,
    >>
    >>Michael
    >>

    >
    > Here's one possible solution:
    >
    > string gsub(const string& sData,
    > const string& sFrom,
    > const string& sTo)
    > {
    > string sNew = sData;
    >
    > if (! sNew.empty())
    > {
    > string::size_type loc;
    >
    > while (string::npos != (loc = sNew.find(sFrom)))
    > sNew.replace(loc, sFrom.length(), sTo);
    > }
    >
    > return sNew;
    > }
    >
    > Regards,
    > Larry



    This one excludes the previouslu scanned text from subsequent
    replacements, in case the 'sTo' text itself (e.g. "Larry Smith")
    includes text that matches 'sFrom' (e.g. "Smith").

    string gsub(const string& sData,
    const string& sFrom,
    const string& sTo)
    {
    string sNew = sData;

    if (! sNew.empty())
    {
    string::size_type toLen = sTo.length();
    string::size_type frLen = sFrom.length();
    string::size_type loc = 0;

    while (string::npos != (loc = sNew.find(sFrom, loc)))
    {
    sNew.replace(loc, frLen, sTo);
    loc += toLen;

    if (loc >= sNew.length())
    break;
    }
    }

    return sNew;
    }

    Regards,
    Larry
    Larry I Smith, Aug 2, 2005
    #12
  13. M

    Guest

    Hi Larry,

    Thanks for the solution, I appreciate it.

    Regards,

    Michael
    , Aug 2, 2005
    #13
  14. M

    Guest

    std::string really sucks.
    no replaceAll, no EndWIth(), no StartWith(), no TrimXX, no auto
    conversion to const char*, etc.
    if you use more than 10 thousands of string in your app, it will take
    more than 100M memory!
    , Aug 2, 2005
    #14
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Alun
    Replies:
    3
    Views:
    4,505
    Masudur
    Feb 18, 2008
  2. Chris M. Thomasson

    automated sub-string search/replace algorithm...

    Chris M. Thomasson, Feb 28, 2010, in forum: C Programming
    Replies:
    40
    Views:
    1,170
    Tim Rentsch
    Mar 26, 2010
  3. Abby Lee
    Replies:
    5
    Views:
    398
    Abby Lee
    Aug 2, 2004
  4. Prasad S
    Replies:
    2
    Views:
    229
    Dr John Stockton
    Aug 27, 2004
  5. V S Rawat
    Replies:
    5
    Views:
    301
    Richard Cornford
    Jul 3, 2007
Loading...

Share This Page