2010-08-05 5 views
141

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

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

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

Но я хотел бы использовать библиотеки Standard C++.

+0

возможно дубликат [Что такое функция для замены строки в C?] (Http://stackoverflow.com/questions/779875/what-is-the-function-to-replace-string-in- c) - oops жаль, что это C, а не C++; Жаль, что я не смогу это сделать. – polygenelubricants

+2

Почему у этого есть тег 'C'? – sbi

+1

@poly Я бы подумал, что этого, должно быть, тоже попросили C++, но я не могу его найти –

ответ

219

Там есть функция, чтобы найти подстроку в строке (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' 
    } 
} 
+2

Как бы исправить это, если в исходной строке было больше одного экземпляра «$ name», и я хотел заменить их все. –

+1

Почему '' '' '' '' '' за ссылку 'const'? Что делает ваша функция, если 'from' там нет? '-1' от меня для этого. – sbi

+0

Добавьте цикл и используйте аргумент «pos» метода find() –

14

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

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

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

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

+0

Из того, что я вижу, метод std :: string replace не принимает две строки, как хотелось бы. –

+0

Я думаю, что у Майкла Мрозека есть более элегантное решение –

+1

Это не работает для меня. sizeof следует заменить строкой («Somename»). size() - 1 – TimZaman

6

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

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

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

+0

Хорошо, я попробую написать свою собственную функцию, чтобы сделать это. –

+1

это size_t, а не size_type – revo

+0

Это std :: string :: size_type, а не size_t или unadorned size_type. – jmucchiello

7

Для того, чтобы иметь новую строку, возвращаемые использовать это:

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 
+0

Ваш вызов subject.replace в ReplaceStringInPlace() - это действительно изменение строки inplace? – Damian

+0

Я кратко посмотрел на источник, и похоже, что он использует семантику перемещения, чтобы переместить переднюю часть старой строки на место, чтобы она не копировалась, но вставленная новая часть копируется в старую строку и хвост старого строка копируется в измененную буферизацию старой строки. Возможно, что строка расширяется настолько, что весь базовый буфер перераспределяется, но если вы замените 1 на 1, как в своем примере, я думаю, что это происходит «на месте» или без какого-либо копирования, но если вы расширите строку, только первая часть старой строки не копируется и может быть только тогда. – Motes

2
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

Не могли бы вы объяснить этот код (в вашем ответе)? Вы можете получить больше авансов таким образом! –

1

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

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() возвращает позицию матча, у нас нет проблемы с недействительными итераторами.

+0

Функция replace() работает отлично. Но в случае, если переменная ** из ** пуста, она входит в бесконечный цикл. std :: string a ("Hello"); заменить (a, "", "мир"); – Hill

+0

@Hill Спасибо, что заметили это! Я думал, что 'std :: string :: find' вернет' npos', если вы не дали ничего, чтобы найти, но, по-видимому, нет! Исправлена. – Galik

51

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

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

двойной обратный слэш требуется для экранирования экранирующего символа.

+0

Я уверен, что 'std :: regex_replace' не принимает строку Qt. – BartoszKP

+1

Вы правы. Так как это происходит, QString предоставляет метод замены, который принимает QRexExp, позволяя использовать собственные материалы Qt. Но я думаю, что текущий ответ можно было бы исправить, заменив 'string' на' string.toStdString() '. – Tom

+1

Или просто изменив 'String' на' std :: string', потому что вопрос не связан с Qt. Пожалуйста, подумайте об этом - я с радостью последую вашему ответу. – BartoszKP

4

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

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

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

+0

Как и стиль, но нашел разные строки, путающие ^^ 'str.replace (str.find («% s »), строка («% s »). Size(),« Something »);' –

0

Я только сейчас изучаю 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; 
} 
0
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); 
3

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

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

Это заменяет sHaystack inline - не нужно делать a = присваивание на этом.

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

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

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

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

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

И пример кода 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, '\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"; 

}