views:

444

answers:

7

What is the best way to replace characters in a string?

Specifically:

"This,Is A|Test" ----> "This_Is_A_Test"

I want to replace all commas, spaces, and "|" with underscores.

(I have access to Boost.)

A: 

The C++ Standard Library has access to these functions as well without using BOOST. Refer to the replace C++ Reference. Is this the best way ? I guess that's up to discussion. To replace multiple / different characters, you may have to call replace more than once.

#include <string>
    string& replace( size_type index, size_type num, const string& str );
    string& replace( size_type index1, size_type num1, const string& str, size_type index2, size_type num2 );
    string& replace( size_type index, size_type num, const Char* str );
    string& replace( size_type index, size_type num1, const Char* str, size_type num2 );
    string& replace( size_type index, size_type num1, size_type num2, Char ch);

    string& replace( iterator start, iterator end, const string& str );
    string& replace( iterator start, iterator end, const Char* str );
    string& replace( iterator start, iterator end, const Char* str, size_type num );
    string& replace( iterator start, iterator end, size_type num, Char ch );
    string& replace( iterator start, iterator end, input_iterator start2, input_iterator end2 );

Example program:

// replacing in a string
#include <iostream>
#include <string>
using namespace std;

int main ()
{
  string base="this is a test string.";
  string str2="n example";
  string str3="sample phrase";
  string str4="useful.";

  // function versions used in the same order as described above:

  // Using positions:                 0123456789*123456789*12345
  string str=base;                // "this is a test string."
  str.replace(9,5,str2);          // "this is an example string."
  str.replace(19,6,str3,7,6);     // "this is an example phrase."
  str.replace(8,10,"just all",6); // "this is just a phrase."
  str.replace(8,6,"a short");     // "this is a short phrase."
  str.replace(22,1,3,'!');        // "this is a short phrase!!!"

  // Using iterators:                      0123456789*123456789*
  string::iterator it = str.begin();   //  ^
  str.replace(it,str.end()-3,str3);    // "sample phrase!!!"
  str.replace(it,it+6,"replace it",7); // "replace phrase!!!"
  it+=8;                               //          ^
  str.replace(it,it+6,"is cool");      // "replace is cool!!!"
  str.replace(it+4,str.end()-4,4,'o'); // "replace is cooool!!!"
  it+=3;                               //             ^
  str.replace(it,str.end(),str4.begin(),str4.end());
                                       // "replace is useful."
  cout << str << endl;
  return 0;
}
0A0D
The replace method just replaces one character (range), not all occurrences of something, so I'd say it is indeed not very helpful for this task :)
UncleBens
Roger. That's why I said it needs to be ran more than once. Whether it is the best methodology, is up to the developer
0A0D
Actually you might be making the water more muddy. `string::replace` is for replacing a single range with another string (or character(s)). OP wants to replace only single characters, so instead of the heavy-weight replace method you could have pointed at operator[], which allows you to "replace" the value of single characters.
UncleBens
+3  A: 

EDIT: As Space_C0wb0y said, replace_if is definitely better. Here's some simpler sample code:

#include <string>
#include <iostream>
#include <algorithm>
using namespace std;

bool isBad(char c)
{
 const string bad_chars = "|, ";
 return (bad_chars.find(c) != string::npos);
}

int main()
{
 string str = "This,Is A|Test";

 // Replace!
 replace_if(str.begin(),str.end(),isBad,'_');

 cout<<str<<endl; 
 return 0;
}

OLD ANSWER:

Use std::replace with std::find_first_of

Jacob
+11  A: 

You could use the STL-Algorithm replace_if.

Space_C0wb0y
A: 

boost::replace_all(s, old, new);

Captain Comic
+8  A: 

As the other answers indicated, you can use the various replace methods. However, these approaches have the downside of scanning the string multiple times (one time for each character). I would recommend rolling your own replace method, if you care about speed:

void beautify(std::string &s) {
    int i;
    for (i = 0; i < s.length(); ++i) {
        switch (s[i]) {
        case ' ':
        case ',':
        case '|':
            s[i] = '_';
        }
    }
}
notnoop
the one line replace method is nice, but your solution works well too
0A0D
One line replace is definitely nicer (I think you will need lines at least), but it's not as efficient.
notnoop
+1 - valid, efficient, longer solution :)
Jacob
I don't think `replace_if` will scan the string multiple times.
Brian
A: 

I was writing this, when Space_C0wb0y posted his answer, which is the right answer for your question. This is a bit more complicated, but handles more possible replacements.

(sorry, not compiled/tested)

class MyReplacer
{
  friend std::ostream& operator<<(std::ostream& os, const MyReplacer& Repl);
  public:
    MyReplacer(char c) : ch(c) {}
  private:
    char ch;
};

std::ostream& operator<<(std::ostream& os, const MyReplacer& Repl)
{
  switch (Repl.ch)
  {
    case '|':
    case ' ':
    case ',': os << '_'; break;
    default: os << Repl.ch;
  }
  return os;
}


std::ostringstream oss;
std::copy(str.begin(), str.end(), std::ostream_iterator<MyReplacer>(oss));
std::string result = oss.str();
stefaanv
+13  A: 

You could use the standard replace_if algorithm, except the predicate is rather complicated (to be expressed inline with current C++ standard and no lambda).

You could write your own, or use is_any_of from boost's string algorithms, so:

#include <algorithm>
#include <string>
#include <boost/algorithm/string/classification.hpp>
#include <iostream>

int main()
{
    std::string s("This,Is A|Test");
    std::replace_if(s.begin(), s.end(), boost::is_any_of(", |"), '_');
    std::cout << s << '\n';
}
UncleBens