Existe-t-il un moyen de remplacer toutes les occurrences d'une sous-chaîne par une autre chaîne dans std::string
?
Par exemple:
void SomeFunction(std::string& str)
{
str = str.replace("hello", "world"); //< I'm looking for something Nice like this
}
Pourquoi ne pas mettre en place votre propre remplacement?
void myReplace(std::string& str,
const std::string& oldStr,
const std::string& newStr)
{
std::string::size_type pos = 0u;
while((pos = str.find(oldStr, pos)) != std::string::npos){
str.replace(pos, oldStr.length(), newStr);
pos += newStr.length();
}
}
#include <boost/algorithm/string.hpp> // include Boost, a C++ library
...
std::string target("Would you like a foo of chocolate. Two foos of chocolate?");
boost::replace_all(target, "foo", "bar");
Voici la documentation officielle on replace_all.
En C++ 11, vous pouvez le faire en une ligne avec un appel à regex_replace
:
#include <string>
#include <regex>
using std::string;
string do_replace( string const & in, string const & from, string const & to )
{
return std::regex_replace( in, std::regex(from), to );
}
string test = "Remove all spaces";
std::cout << do_replace(test, " ", "") << std::endl;
sortie:
Removeallspaces
Pourquoi ne pas retourner une chaîne modifiée?
std::string ReplaceString(std::string subject, const std::string& search,
const std::string& replace) {
size_t pos = 0;
while((pos = subject.find(search, pos)) != std::string::npos) {
subject.replace(pos, search.length(), replace);
pos += replace.length();
}
return subject;
}
Si vous avez besoin de performances, voici une fonction optimisée qui modifie la chaîne d'entrée, elle ne crée pas de copie de la chaîne:
void ReplaceStringInPlace(std::string& subject, const std::string& search,
const std::string& replace) {
size_t pos = 0;
while((pos = subject.find(search, pos)) != std::string::npos) {
subject.replace(pos, search.length(), replace);
pos += replace.length();
}
}
Tests:
std::string input = "abc abc def";
std::cout << "Input string: " << input << std::endl;
std::cout << "ReplaceString() return value: "
<< ReplaceString(input, "bc", "!!") << std::endl;
std::cout << "ReplaceString() input string not changed: "
<< input << std::endl;
ReplaceStringInPlace(input, "bc", "??");
std::cout << "ReplaceStringInPlace() input string modified: "
<< input << std::endl;
Sortie:
Input string: abc abc def
ReplaceString() return value: a!! a!! def
ReplaceString() input string not modified: abc abc def
ReplaceStringInPlace() input string modified: a?? a?? def
Mon système de recherche et de remplacement sur place en ligne modèle:
template<class T>
int inline findAndReplace(T& source, const T& find, const T& replace)
{
int num=0;
typename T::size_t fLen = find.size();
typename T::size_t rLen = replace.size();
for (T::size_t pos=0; (pos=source.find(find, pos))!=T::npos; pos+=rLen)
{
num++;
source.replace(pos, fLen, replace);
}
return num;
}
Il retourne le nombre d'éléments substitués (à utiliser si vous voulez exécuter ceci successivement, etc.). Pour l'utiliser:
std::string str = "one two three";
int n = findAndReplace(str, "one", "1");
Le moyen le plus simple (offrant quelque chose à côté de ce que vous avez écrit) est d'utiliser Boost.Regex , plus précisément regex_replace .
std :: string a construit dans les méthodes find () et replace (), mais il est plus difficile de travailler avec car ils nécessitent de traiter avec des index et des longueurs de chaîne.
Je crois que cela fonctionnerait .. Il faut que const char * soit un paramètre.
//params find and replace cannot be NULL
void FindAndReplace( std::string& source, const char* find, const char* replace )
{
//ASSERT(find != NULL);
//ASSERT(replace != NULL);
size_t findLen = strlen(find);
size_t replaceLen = strlen(replace);
size_t pos = 0;
//search for the next occurrence of find within source
while ((pos = source.find(find, pos)) != std::string::npos)
{
//replace the found string with the replacement
source.replace( pos, findLen, replace );
//the next line keeps you from searching your replace string,
//so your could replace "hello" with "hello world"
//and not have it blow chunks.
pos += replaceLen;
}
}
#include <iostream>
#include <string>
#include <boost/algorithm/string.hpp>
#include <boost/tokenizer.hpp>
#include <boost/foreach.hpp>
using namespace boost::algorithm;
using namespace std;
using namespace boost;
void highlighter(string terms, string text) {
char_separator<char> sep(" ");
tokenizer<char_separator<char> > tokens(terms, sep);
BOOST_FOREACH(string term, tokens) {
boost::replace_all(text, term, "<b>" + term + "</b>");
}
cout << text << endl;
}
int main(int argc, char **argv)
{
cout << "Search term highlighter" << endl;
string text("I love boost library, and this is a test of boost library!");
highlighter("love boost", text);
}
Je amourrenforcer bibliothèque, et ceci est un test de renforcer bibliothèque!
// Replace all occurrences of searchStr in str with replacer
// Each match is replaced only once to prevent an infinite loop
// The algorithm iterates once over the input and only concatenates
// to the output, so it should be reasonably efficient
std::string replace(const std::string& str, const std::string& searchStr,
const std::string& replacer)
{
// Prevent an infinite loop if the input is empty
if (searchStr == "") {
return str;
}
std::string result = "";
size_t pos = 0;
size_t pos2 = str.find(searchStr, pos);
while (pos2 != std::string::npos) {
result += str.substr(pos, pos2-pos) + replacer;
pos = pos2 + searchStr.length();
pos2 = str.find(searchStr, pos);
}
result += str.substr(pos, str.length()-pos);
return result;
}
#include <string>
using std::string;
void myReplace(string& str,
const string& oldStr,
const string& newStr) {
if (oldStr.empty()) {
return;
}
for (size_t pos = 0; (pos = str.find(oldStr, pos)) != string::npos;) {
str.replace(pos, oldStr.length(), newStr);
pos += newStr.length();
}
}
Le contrôle pour que oldStr soit vide est important. Si pour une raison quelconque ce paramètre est vide, vous serez bloqué dans une boucle infinie.
Mais oui, utilisez la solution C++ 11 ou Boost, qui a fait ses preuves, si vous le pouvez.