How to replace all occurrences of one character with two characters using std::string?

27,904

Solution 1

Probably the simplest way to get this done is with boost string algorithms library.

  boost::replace_all(myString, "/", "\\/");

  std::string result = boost::replace_all_copy(myString, "/", "\\/");

Solution 2

The answer is no... there is no "easy" way if you mean an one-liner already provided by the standard library. However it's not hard to implement that function.

First of all I think that probably you will also need to replace \ with \\ and other special characters. In this case using the replaceAll implementation given by ildjarn is going to be annoying (you'll need to replace the same string several times).

In my opinion there are many cases of string processing where nothing beats using an explicit char * approach. In this specific case however probably just using an index is fine:

std::string escape(const std::string& s)
{
    int n = s.size(), wp = 0;
    std::vector<char> result(n*2);
    for (int i=0; i<n; i++)
    {
        if (s[i] == '/' || s[i] == '\\')
            result[wp++] = '\\';
        result[wp++] = s[i];
    }
    return std::string(&result[0], &result[wp]);
}

Basically the idea is to move over the string and adding an extra \ character before any special character (in the above I just handled / and \, but you get the idea). The result is known to be at maximum 2*n in lenght, so I preallocate it making the whole processing O(n) (the replaceAll approach instead keeps moving the rest of the string to the right, making it O(n^2)). Even for short strings like "this is a test with /slashes/ that should be /escaped/" the above function is on my PC more efficient (1.3x in speed) even if calling replaceAll just once and handling instead two special chars in escape.

Note also that this function naturally returns a separate string instead of modifying the string in place (IMO a better interface) and in the timing comparison I had to create a string for each call so the results are even shifted toward equality because of that added constant time.

The above read/write approach can also be easily extended to more complex substitutions (e.g. replacing > with &gt; or characters not in printable range with %xx encoding) still maintaining a good efficiency for big strings (just one pass).

Solution 3

An example on how to do this is given on the cppreference.com std::string::replace page:

std::string& replaceAll(std::string& context, std::string const& from, std::string const& to)
{
    std::size_t lookHere = 0;
    std::size_t foundHere;
    while((foundHere = context.find(from, lookHere)) != std::string::npos)
    {
          context.replace(foundHere, from.size(), to);
          lookHere = foundHere + to.size();
    }
    return context;
}

Solution 4

To replace all the occurences of a sub-string in a string by another sub-string:

#include <iostream>

void replace_all(std::string& input, const std::string& from, const std::string& to) {
  size_t pos = 0;
  while ((pos = input.find(from, pos)) != std::string::npos) {
    input.replace(pos, from.size(), to);
    pos += to.size();
  }
}

int main() {
  std::string str("i am a geek/nerd/crazy person.");
  replace_all(str, "/", "\\/");
  std::cout << str << '\n';
}

Output:

$ g++-6.1.0 -std=c++17 -g -Og -Werror -Wall -Wextra -pedantic -Wold-style-cast -Wnon-virtual-dtor -Wshadow -Wcast-align -Wunused -Woverloaded-virtual -Wconversion -Wsign-conversion -Wmisleading-indentation -fsanitize=address,leak,undefined; ./a.out
i am a geek\/nerd\/crazy person.

Solution 5

std::string::replace

Share:
27,904
WilliamKF
Author by

WilliamKF

Updated on July 27, 2022

Comments

  • WilliamKF
    WilliamKF almost 2 years

    Is there a nice simple way to replace all occurrences of "/" in a std::string with "\/" to escape all the slashes in a std::string?