Как заменить все вхождения символа в строку?


каков эффективный способ заменить все вхождения символа другим символом в std::string?

12 400

12 ответов:

std::string Не содержит такой функции, но вы можете использовать автономный

Я думал, что брошу в импульс решению а также:

#include <boost/algorithm/string/replace.hpp>

// in place
std::string in_place = "blah#blah";
boost::replace_all(in_place, "#", "@");

// copy
const std::string input = "blah#blah";
std::string output = boost::replace_all_copy(input, "#", "@");

вопрос сосредоточен на character замена, но, как я нашел эту страницу, очень полезно (особенно Конрадзамечание), я хотел бы поделиться этой более обобщенной реализацией, которая позволяет иметь дело с substrings а также:

std::string ReplaceAll(std::string str, const std::string& from, const std::string& to) {
    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(); // Handles case where 'to' is a substring of 'from'
    }
    return str;
}

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

std::cout << ReplaceAll(string("Number Of Beans"), std::string(" "), std::string("_")) << std::endl;
std::cout << ReplaceAll(string("ghghjghugtghty"), std::string("gh"), std::string("X")) << std::endl;
std::cout << ReplaceAll(string("ghghjghugtghty"), std::string("gh"), std::string("h")) << std::endl;

выходы:

Number_Of_Beans

XXjXugtXty

hhjhugthty


EDIT:

вышесказанное может быть реализовано более подходящим способом, в случае, если выступления вас беспокоят, ничего не возвращая (void) и выполнение изменений непосредственно в строке str задано в качестве аргумента, передано по адресу вместо по стоимости. Это позволит избежать бесполезной и дорогостоящей копии исходной строки, возвращая результат. Ваш звонок, затем...

код :

static inline void ReplaceAll2(std::string &str, const std::string& from, const std::string& to)
{
    // Same inner code...
    // No return statement
}

надеюсь, это будет полезно для других...

представьте себе большой двоичный большой двоичный объект, где все 0x00 байт должны быть заменены на " \1\x30 "и все 0x01 байт на" \1\x31", потому что транспортный протокол не допускает \0-байт.

в случаях, когда:

  • заменяющая и заменяемая строка имеют разную длину,
  • есть много вхождений строки to-replaced в исходной строке и
  • исходная строка большой,

решения не может быть применяется (потому что они заменяют только отдельные символы) или имеют проблемы с производительностью, потому что они будут вызывать string::replace несколько раз, который генерирует копии размера большого двоичного объекта снова и снова. (Я не знаю решение boost, может быть, это нормально с этой точки зрения)

этот ходит по всем вхождениям в исходной строке и строит новую строку по частям после:

void replaceAll(std::string& source, const std::string& from, const std::string& to)
{
    std::string newString;
    newString.reserve(source.length());  // avoids a few memory allocations

    std::string::size_type lastPos = 0;
    std::string::size_type findPos;

    while(std::string::npos != (findPos = source.find(from, lastPos)))
    {
        newString.append(source, lastPos, findPos - lastPos);
        newString += to;
        lastPos = findPos + from.length();
    }

    // Care for the rest after last occurrence
    newString += source.substr(lastPos);

    source.swap(newString);
}

простой поиск и замена для одного символа будет идти что-то вроде:

s.replace(s.find("x"), 1, "y")

чтобы сделать это для всей строки, легко было бы сделать цикл до вашего s.find начинается возвращение npos. Я полагаю, вы могли бы также поймать range_error выйти из цикла, но это как-то некрасиво.

Если вы хотите заменить более одного символа, и имеете дело только с std::string, тогда этот фрагмент будет работать, заменяя sNeedle в sHaystack на sReplace, а sNeedle и sReplace не должны быть одинакового размера. Эта процедура использует цикл while для замены всех вхождений, а не только первого, найденного слева направо.

while(sHaystack.find(sNeedle) != std::string::npos) {
  sHaystack.replace(sHaystack.find(sNeedle),sNeedle.size(),sReplace);
}

Как предложил Кирилл, либо используйте метод replace, либо повторяйте по строке, заменяя каждый символ независимо.

в качестве альтернативы вы можете использовать find способ или find_first_of в зависимости от того, что нужно делать. Ни одно из этих решений не сделает работу за один раз, но с несколькими дополнительными строками кода Вы должны заставить их работать на вас. : -)

#include <iostream>
#include <string>
using namespace std;
// Replace function..
string replace(string word, string target, string replacement){
    int len, loop=0;
    string nword="", let;
    len=word.length();
    len--;
    while(loop<=len){
        let=word.substr(loop, 1);
        if(let==target){
            nword=nword+replacement;
        }else{
            nword=nword+let;
        }
        loop++;
    }
    return nword;

}
//Main..
int main() {
  string word;
  cout<<"Enter Word: ";
  cin>>word;
  cout<<replace(word, "x", "y")<<endl;
  return 0;
}

это работает! Я использовал что-то подобное для приложения книжного магазина, где инвентарь хранился в CSV (например .DAT-файл). Но в случае одного символа, то есть заменитель является только одним символом, например||', он должен быть в двойных кавычках"/", чтобы не выбрасывать недопустимое преобразование const char.

#include <iostream>
#include <string>

using namespace std;

int main()
{
    int count = 0;  // for the number of occurences.
    // final hold variable of corrected word up to the npos=j
    string holdWord = "";
    // a temp var in order to replace 0 to new npos
    string holdTemp = "";
    // a csv for a an entry in a book store
    string holdLetter = "Big Java 7th Ed,Horstman,978-1118431115,99.85";

    // j = npos
    for (int j = 0; j < holdLetter.length(); j++) {

        if (holdLetter[j] == ',') {

            if ( count == 0 ) 
            {           
                holdWord = holdLetter.replace(j, 1, " | ");      
            }
            else {

                string holdTemp1 = holdLetter.replace(j, 1, " | ");

                // since replacement is three positions in length,
                // must replace new replacement's 0 to npos-3, with
                // the 0 to npos - 3 of the old replacement 
                holdTemp = holdTemp1.replace(0, j-3, holdWord, 0, j-3); 

                holdWord = "";

                holdWord = holdTemp;

            }
            holdTemp = "";
            count++;
        }
    } 
    cout << holdWord << endl;
    return 0;
}

// result:
Big Java 7th Ed | Horstman | 978-1118431115 | 99.85

В настоящее время я использую CentOS, поэтому моя версия компилятора приведена ниже . Версия C++ (g++), C++98 по умолчанию:

g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-4)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

если вы используете std::strings, Вы можете использовать этот образец-приложение strsub функции как есть, или обновить его, если вы хотите его взять другой тип или набор параметров для достижения примерно той же цели. В основном, он использует свойства и функциональные возможности std::string чтобы быстро стереть соответствующий набор символов и вставить нужные символы непосредственно в std::string. Каждый раз, когда он выполняет эту операцию замены, смещение обновляется, если он все еще может найти соответствующие символы заменить, и если он не может из-за ничего больше заменить, он возвращает строку в ее состоянии из последнего обновления.

#include <iostream>
#include <string>

std::string strsub(std::string stringToModify,
                   std::string charsToReplace,
                   std::string replacementChars);

int main()
{
    std::string silly_typos = "annoiiyyyng syyyllii tiipos.";

    std::cout << "Look at these " << silly_typos << std::endl;
    silly_typos = strsub(silly_typos, "yyy", "i");
    std::cout << "After a little elbow-grease, a few less " << silly_typos << std::endl;
    silly_typos = strsub(silly_typos, "ii", "y");

    std::cout << "There, no more " << silly_typos << std::endl;
    return 0;
}

std::string strsub(std::string stringToModify,
                   std::string charsToReplace,
                   std::string replacementChars)
{
    std::string this_string = stringToModify;

    std::size_t this_occurrence = this_string.find(charsToReplace);
    while (this_occurrence != std::string::npos)
    {
        this_string.erase(this_occurrence, charsToReplace.size());
        this_string.insert(this_occurrence, replacementChars);
        this_occurrence = this_string.find(charsToReplace,
                                           this_occurrence + replacementChars.size());
    }

    return this_string;
}

если вы не хотите полагаться на использование std::strings в качестве параметров, чтобы вы могли передавать строки в стиле C, вы можете увидеть обновленный пример ниже:

#include <iostream>
#include <string>

std::string strsub(const char * stringToModify,
                   const char * charsToReplace,
                   const char * replacementChars,
                   uint64_t sizeOfCharsToReplace,
                   uint64_t sizeOfReplacementChars);

int main()
{
    std::string silly_typos = "annoiiyyyng syyyllii tiipos.";

    std::cout << "Look at these " << silly_typos << std::endl;
    silly_typos = strsub(silly_typos.c_str(), "yyy", "i", 3, 1);
    std::cout << "After a little elbow-grease, a few less " << silly_typos << std::endl;
    silly_typos = strsub(silly_typos.c_str(), "ii", "y", 2, 1);

    std::cout << "There, no more " << silly_typos << std::endl;
    return 0;
}

std::string strsub(const char * stringToModify,
                   const char * charsToReplace,
                   const char * replacementChars,
                   uint64_t sizeOfCharsToReplace,
                   uint64_t sizeOfReplacementChars)
{
    std::string this_string = stringToModify;

    std::size_t this_occurrence = this_string.find(charsToReplace);
    while (this_occurrence != std::string::npos)
    {
        this_string.erase(this_occurrence, sizeOfCharsToReplace);
        this_string.insert(this_occurrence, replacementChars);
        this_occurrence = this_string.find(charsToReplace,
            this_occurrence + sizeOfReplacementChars);
    }

    return this_string;
}

для простых ситуаций это работает довольно хорошо без использования какой-либо другой библиотеки, то std::string (который уже используется).

заменить все вхождения символов a С символов b на some_string:

for (size_t i = 0; i < some_string.size(); ++i) {
    if (some_string[i] == 'a') {
        some_string.replace(i, 1, "b");
    }
}

если строка большая или несколько вызовов для замены является проблемой, вы можете применить метод, упомянутый в этом ответе:https://stackoverflow.com/a/29752943/3622300

Старая Школа :-)

    string pth = "H:/recursos/audio/youtube/libre/falta/";        

    for(int i=0 ;i<=pth.size(); i++)
    if(pth[i]=='/')
    pth[i]='\';

    cout<<pth;

результат: "H:\recursos\audio\youtube\libre\falta\";