Заменить часть строки другой строкой

возможно ли в C++ заменить часть строки другой строкой?

в принципе, я хотел бы сделать это:

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

но я хотел бы использовать стандартные библиотеки C++.

12 ответов


есть функция для поиска подстроки в строке (find), и функция для замены определенного диапазона в строку с другой строкой (replace), поэтому вы можете объединить их, чтобы получить эффект, который вы хотите:

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

в ответ на комментарий, Я думаю,replaceAll вероятно, будет выглядеть примерно так:

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

С C++11 вы можете использовать std::regex вот так:

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

для экранирования escape-символа требуется двойная обратная косая черта.


std::string есть replace метод, это то, что вы ищете?

вы можете попробовать:

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

Я не пробовал сам, просто прочитайте документацию на find() и replace().


чтобы вернуть новую строку, используйте следующее:

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

Если вам нужна производительность, вот оптимизированная функция, которая изменяет входную строку, она не создает копию строки:

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

тесты:

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;

выход:

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

Да, вы можете это сделать, но вы должны найти позицию первой строки с помощью элемента find() строки, а затем заменить его на элемент replace ().

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

Если вы планируете использовать стандартную библиотеку, вы действительно должны получить копию книги Стандартная Библиотека C++ который охватывает все это очень хорошо.


Это звучит как вариант

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

вы могли бы обернуть это в функцию, но это решение звучит приемлемо. Проблема в том, что это изменит только первое появление, вы можете захотеть зациклиться на нем, но он также позволяет вставлять несколько переменных в эту строку с одним и тем же токеном (%s)


если все строки являются std:: string, вы найдете странные проблемы с отсечением символов при использовании sizeof() потому что он предназначен для строк C, а не для строк C++. Исправление заключается в использовании .size() метод класс std::string.

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

это заменяет shaystack inline -- нет необходимости делать = назначение обратно на это.

пример использования:

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;

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

Я использую обычно так:

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

Он неоднократно называет std::string::find(), чтобы найти все вхождения искомой строки до std::string::find() ничего не найти. Потому что std::string::find() возвращает позиция матча у нас нет проблемы недействительности итераторов.


Если вы хотите сделать это быстро, вы можете использовать два подхода сканирования. Псевдо код:

  1. в первую очередь разбирают. найдите, сколько подходящих символов.
  2. разверните длину строки.
  3. второго разбора. Начните с конца строки, когда мы получим совпадение, которое мы заменим, иначе мы просто скопируем символы из первой строки.

Я не уверен, что это можно оптимизировать для Algo на месте.

и пример кода C++11, но я только ищу за один шар.

#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, '');

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

}

Я только сейчас изучаю C++, но редактируя некоторые из ранее опубликованных кодов, я бы, вероятно, использовал что-то вроде этого. Это дает вам гибкость для замены 1 или нескольких экземпляров, а также позволяет указать начальную точку.

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

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