Zastąp część łańcucha innym łańcuchem

Czy w C++ możliwe jest zastąpienie części łańcucha innym łańcuchem?

W zasadzie chciałbym to zrobić:

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

Ale chciałbym użyć standardowych bibliotek C++.

Author: Peter Mortensen, 2010-08-05

12 answers

Istnieje funkcja do znalezienia fragmentu łańcucha (find), Oraz funkcja zastępująca dany zakres w łańcuchu innym łańcuchem (replace), możesz więc połączyć je, aby uzyskać pożądany efekt:

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");

W odpowiedzi na komentarz, myślę, że replaceAll prawdopodobnie wyglądałoby to mniej więcej tak:

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'
    }
}
 238
Author: Michael Mrozek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-28 17:37:34

W C++11 możesz używać std::regex w następujący sposób:

    std::string string("hello $name");
    string = std::regex_replace(string, std::regex("\\$name"), "Somename");

Podwójny Ukośnik jest wymagany do ucieczki znaku escape.

 57
Author: Tom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-25 13:24:54

std::string ma replace metoda, to jest to, czego szukasz?

Możesz spróbować:
s.replace(s.find("$name"), sizeof("Somename")-1, "Somename");

Nie próbowałem sam, tylko przeczytałem dokumentację na find() i replace().

 15
Author: S.C. Madsen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-30 13:56:55

Aby mieć zwrócony nowy łańcuch, użyj tego:

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

Jeśli potrzebujesz wydajności, oto Zoptymalizowana funkcja, która modyfikuje łańcuch wejściowy, nie tworzy kopii łańcucha:

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

Testy:

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;

Wyjście:

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
 7
Author: Czarek Tomczak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-26 01:19:19

Tak, możesz to zrobić, ale musisz znaleźć pozycję pierwszego łańcucha za pomocą elementu find (), a następnie replace za pomocą elementu replace ().

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

Jeśli planujesz korzystać z biblioteki standardowej, powinieneś naprawdę zdobyć kopię książki The C++ Standard Library , która bardzo dobrze obejmuje te wszystkie rzeczy.

 6
Author: Drew Noakes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-09 14:28:27

To brzmi jak opcja

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

Można to zawinąć w funkcję, ale to rozwiązanie Jednowierszowe wydaje się akceptowalne. Problem polega na tym, że zmieni to tylko pierwsze wystąpienie, możesz chcieć zapętlić nad nim pętlę, ale pozwala również wstawić kilka zmiennych do tego ciągu z tym samym tokenem (%s)

 4
Author: maxoumime,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-04 20:29:30

Jeśli wszystkie ciągi są std:: string, znajdziesz dziwne problemy z odcinaniem znaków, jeśli używasz sizeof(), ponieważ jest to przeznaczone dla ciągów C, a nie c++. Poprawką jest użycie metody .size() klasy std::string.

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

Który zastępuje sHaystack inline -- nie trzeba robić przypisania = z powrotem na tym.

Przykładowe użycie:

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;
 3
Author: Volomike,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-04 04:15:26
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;
}
 2
Author: Lucas Civali,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-17 14:08:03

Używam ogólnie tego:

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

Wielokrotnie wywołuje std::string::find() w celu zlokalizowania innych wystąpień szukanego ciągu, dopóki std::string::find() niczego nie znajdzie. Ponieważ std::string::find() zwraca pozycję meczu, nie mamy problemu z unieważnieniem iteratorów.

 1
Author: Galik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-20 12:29:00

Jeśli chcesz zrobić to szybko, możesz użyć podejścia dwóch skanowania. Pseudo kod:

  1. pierwszy parse. znajdź, ile pasujących znaków.
  2. rozwiń Długość łańcucha.
  3. drugi parse. Zaczynamy od końca łańcucha, gdy otrzymamy dopasowanie, które zastępujemy, w przeciwnym razie po prostu kopiujemy znaki z pierwszego łańcucha.

Nie jestem pewien, czy można to zoptymalizować do algo.

I przykład kodu C++11, ale szukam tylko jednego znaku.

#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";

}
 1
Author: Damian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-13 11:38:52

Właśnie uczę się C++, ale edytując część wcześniej zamieszczonego kodu, prawdopodobnie użyłbym czegoś takiego. Daje to możliwość zastąpienia 1 lub wielu wystąpień, a także pozwala określić punkt początkowy.

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;
}
 0
Author: someprogrammer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-07 16:55:43
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);
 0
Author: user3016543,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-27 16:37:45