Как заменить все вхождения символа в строку?
каков эффективный способ заменить все вхождения символа другим символом в std::string
?
12 ответов:
Я думал, что брошу в импульс решению а также:
#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::string
s, Вы можете использовать этот образец-приложение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::string
s в качестве параметров, чтобы вы могли передавать строки в стиле 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