Vervang een deel van een string door een andere string

Is het mogelijk in C++ om een deel van een string te vervangen door een andere string?

In principe zou ik dit willen doen:

QString string("hello $name");
string.replace("$name", "Somename");

Maar ik wil graag de standaard C++-bibliotheken gebruiken.


Antwoord 1, autoriteit 100%

Er is een functie om een subtekenreeks binnen een tekenreeks te vinden (find), en een functie om een bepaald bereik in een tekenreeks te vervangen door een andere tekenreeks (replace), zodat u deze kunt combineren om het gewenste effect te krijgen:

bool replace(std::string& str, const std::string& from, const std::string& to) {
    size_t start_pos = str.find(from);
    if(start_pos == std::string::npos)
        return false;
    str.replace(start_pos, from.length(), to);
    return true;
}
std::string string("hello $name");
replace(string, "$name", "Somename");

Als reactie op een opmerking denk ik dat replaceAller ongeveer zo uit zou zien:

void replaceAll(std::string& str, const std::string& from, const std::string& to) {
    if(from.empty())
        return;
    size_t start_pos = 0;
    while((start_pos = str.find(from, start_pos)) != std::string::npos) {
        str.replace(start_pos, from.length(), to);
        start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
    }
}

Antwoord 2, autoriteit 40%

Met C++11 kun je std::regexals volgt gebruiken:

#include <regex>
...
std::string string("hello $name");
string = std::regex_replace(string, std::regex("\\$name"), "Somename");

De dubbele backslash is vereist om een escape-teken te escapen.


Antwoord 3, autoriteit 7%

std::stringheeft een replacemethode, is dat wat u zoekt?

Je zou kunnen proberen:

s.replace(s.find("$name"), sizeof("$name") - 1, "Somename");

Ik heb het zelf niet geprobeerd, lees alleen de documentatie op find()en replace().


Antwoord 4, autoriteit 3%

Gebruik dit om de nieuwe string terug te laten komen:

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;
}

Als je prestaties nodig hebt, is hier een geoptimaliseerde functie die de invoertekenreeks aanpast, het maakt geen kopie van de tekenreeks:

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();
    }
}

Testen:

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 modified: " 
          << input << std::endl;
ReplaceStringInPlace(input, "bc", "??");
std::cout << "ReplaceStringInPlace() input string modified: " 
          << input << std::endl;

Uitvoer:

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

Antwoord 5, autoriteit 2%

Ja, dat kan, maar je moet de positie van de eerste tekenreeks vinden met het zoek()-lid van de tekenreeks, en dan vervangen door zijn vervang()-lid.

string s("hello $name");
size_type pos = s.find( "$name" );
if ( pos != string::npos ) {
   s.replace( pos, 5, "somename" );   // 5 = length( $name )
}

Als u van plan bent de Standaardbibliotheek te gebruiken, moet u echt een exemplaar van het boek De C++ Standard Librarydie al deze dingen heel goed dekt.


Antwoord 6, autoriteit 2%

Dit klinkt als een optie

string.replace(string.find("%s"), string("%s").size(), "Something");

Je zou dit in een functie kunnen stoppen, maar deze eenregelige oplossing klinkt acceptabel.
Het probleem is dat dit alleen de eerste voorkeur zal veranderen, misschien wilt u erover lussen, maar het kunt ook meerdere variabelen in deze reeks plaatsen met dezelfde token (%s)


Antwoord 7, Autoriteit 2%

Ik gebruik meestal dit:

std::string& replace(std::string& s, const std::string& from, const std::string& to)
{
    if(!from.empty())
        for(size_t pos = 0; (pos = s.find(from, pos)) != std::string::npos; pos += to.size())
            s.replace(pos, from.size(), to);
    return s;
}

Het roept herhaaldelijk in std::string::find()om andere voorvallen van de doorzochte reeks te vinden tot std::string::find()DOSN ‘ t Zoek alles. Omdat std::string::find()Retourneert de Positie van de wedstrijd We hebben niet het probleem van ongeldige iterators.


Antwoord 8

Als alle snaren std :: String, vindt u vreemde problemen met de cutoff van tekens als u sizeof()gebruikt, omdat het bedoeld is voor C-snaren, niet C++ snaren. De fix is ​​om de .size()class-methode van std::string.

sHaystack.replace(sHaystack.find(sNeedle), sNeedle.size(), sReplace);

Dat vervangt Shaystack-inline – niet nodig om een ​​= toewijzing daarover te doen.

Voorbeeld Gebruik:

std::string sHaystack = "This is %XXX% test.";
std::string sNeedle = "%XXX%";
std::string sReplace = "my special";
sHaystack.replace(sHaystack.find(sNeedle),sNeedle.size(),sReplace);
std::cout << sHaystack << std::endl;

Antwoord 9

wstring myString = L"Hello $$ this is an example. By $$.";
wstring search = L"$$";
wstring replace = L"Tom";
for (int i = myString.find(search); i >= 0; i = myString.find(search))
    myString.replace(i, search.size(), replace);

Antwoord 10

Als u het snel wilt doen, kunt u een benadering met twee scans gebruiken.
Pseudo-code:

  1. eerste ontleden. vind hoeveel overeenkomende tekens.
  2. vergroot de lengte van de string.
  3. tweede ontleden. Begin vanaf het einde van de tekenreeks wanneer we een overeenkomst krijgen die we vervangen, anders kopiëren we gewoon de tekens van de eerste tekenreeks.

Ik weet niet zeker of dit kan worden geoptimaliseerd tot een in-place algo.

En een voorbeeld van een C++11-code, maar ik zoek maar naar één teken.

#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
void ReplaceString(string& subject, char search, const string& replace)
{   
    size_t initSize = subject.size();
    int count = 0;
    for (auto c : subject) { 
        if (c == search) ++count;
    }
    size_t idx = subject.size()-1 + count * replace.size()-1;
    subject.resize(idx + 1, '\0');
    string reverseReplace{ replace };
    reverse(reverseReplace.begin(), reverseReplace.end());  
    char *end_ptr = &subject[initSize - 1];
    while (end_ptr >= &subject[0])
    {
        if (*end_ptr == search) {
            for (auto c : reverseReplace) {
                subject[idx - 1] = c;
                --idx;              
            }           
        }
        else {
            subject[idx - 1] = *end_ptr;
            --idx;
        }
        --end_ptr;
    }
}
int main()
{
    string s{ "Mr John Smith" };
    ReplaceString(s, ' ', "%20");
    cout << s << "\n";
}

Antwoord 11

Dit kan nog beter zijn om

te gebruiken

void replace(string& input, const string& from, const string& to)
{
    while(true)
    {
        size_t startPosition = input.find(from);
        if(startPosition == string::npos)
            break;
        input.replace(startPosition, from.length(), to);
    }
}

Antwoord 12

std::string replace(std::string base, const std::string from, const std::string to) {
    std::string SecureCopy = base;
    for (size_t start_pos = SecureCopy.find(from); start_pos != std::string::npos; start_pos = SecureCopy.find(from,start_pos))
    {
        SecureCopy.replace(start_pos, from.length(), to);
    }
    return SecureCopy;
}

Antwoord 13

Mijn eigen implementatie, rekening houdend met die string moet slechts één keer worden verkregen, dan kan vervangen.

template <typename T>
std::basic_string<T> replaceAll(const std::basic_string<T>& s, const T* from, const T* to)
{
    auto length = std::char_traits<T>::length;
    size_t toLen = length(to), fromLen = length(from), delta = toLen - fromLen;
    bool pass = false;
    std::string ns = s;
    size_t newLen = ns.length();
    for (bool estimate : { true, false })
    {
        size_t pos = 0;
        for (; (pos = ns.find(from, pos)) != std::string::npos; pos++)
        {
            if (estimate)
            {
                newLen += delta;
                pos += fromLen;
            }
            else
            {
                ns.replace(pos, fromLen, to);
                pos += delta;
            }
        }
        if (estimate)
            ns.resize(newLen);
    }
    return ns;
}

Het gebruik kan bijvoorbeeld als volgt zijn:

std::string dirSuite = replaceAll(replaceAll(relPath.parent_path().u8string(), "\\", "/"), ":", "");

Antwoord 14

Ik ben nu pas C++ aan het leren, maar als ik een deel van de eerder geposte code aan het bewerken ben, zou ik waarschijnlijk zoiets als dit gebruiken. Dit geeft je de flexibiliteit om 1 of meerdere instanties te vervangen, en laat je ook het startpunt specificeren.

using namespace std;
// returns number of replacements made in string
long strReplace(string& str, const string& from, const string& to, size_t start = 0, long count = -1) {
    if (from.empty()) return 0;
    size_t startpos = str.find(from, start);
    long replaceCount = 0;
    while (startpos != string::npos){
        str.replace(startpos, from.length(), to);
        startpos += to.length();
        replaceCount++;
        if (count > 0 && replaceCount >= count) break;
        startpos = str.find(from, startpos);
    }
    return replaceCount;
}

Antwoord 15

U kunt deze code gebruiken voor het verwijderen van subtring en ook voor vervangen, en ook voor het verwijderen van extra witruimte .
code :

#include<bits/stdc++.h>
using namespace std ;
void removeSpaces(string &str)
{
    int n = str.length();
    int i = 0, j = -1;
    bool spaceFound = false;
    while (++j <= n && str[j] == ' ');
    while (j <= n)
    {
        if (str[j] != ' ')
        {
            if ((str[j] == '.' || str[j] == ',' ||
                 str[j] == '?') && i - 1 >= 0 &&
                 str[i - 1] == ' ')
                str[i - 1] = str[j++];
            else
                str[i++] = str[j++];
            spaceFound = false;
        }
        else if (str[j++] == ' ')
        {
            if (!spaceFound)
            {
                str[i++] = ' ';
                spaceFound = true;
            }
        }
    }
    if (i <= 1)
        str.erase(str.begin() + i, str.end());
    else
        str.erase(str.begin() + i - 1, str.end());
}
int main()
{
    string s;
    cin>>s;
    for(int i=s.find("WUB");i>=0;i=s.find("WUB"))
    {
        s.replace(i,3," ");
    }
    removeSpaces(s);
    cout<<s<<endl;
    return 0;
}

Other episodes