Odpowiedzi:
std::string
nie zawiera takiej funkcji, ale można użyć replace
funkcji autonomicznej z algorithm
nagłówka.
#include <algorithm>
#include <string>
void some_func() {
std::string s = "example string";
std::replace( s.begin(), s.end(), 'x', 'y'); // replace all 'x' to 'y'
}
std::string::replace()
zamiast std::replace()
! „x” ( char
) jest domyślnie rzutowane na size_t
[wartość 120], dlatego cały ciąg lub jego część zostanie wypełniona 120 kopiami „y”.
Pomyślałem, że wrzucę również rozwiązanie doładowania :
#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, "#", "@");
-I
flag dla kompilatora, aby mógł on znaleźć biblioteki Boost w twoim systemie. Być może najpierw musisz go zainstalować.
Pytanie koncentruje się na character
wymianie, ale ponieważ uznałem tę stronę za bardzo przydatną (szczególnie uwagę Konrada ), chciałbym udostępnić tę bardziej uogólnioną implementację, która pozwala również poradzić sobie z 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;
}
Stosowanie:
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;
Wyjścia:
Number_Of_Beans
XXjXugtXty
hhjhugthty
EDYTOWAĆ:
Powyższe można zaimplementować w bardziej odpowiedni sposób, w przypadku gdy wydajność ma znaczenie, zwracając nic ( void
) i wykonując zmiany bezpośrednio na łańcuchu str
podanym jako argument, przekazywany przez adres zamiast wartości . Pozwoliłoby to uniknąć niepotrzebnej i kosztownej kopii oryginalnego ciągu, zwracając jednocześnie wynik. Twoje połączenie, a następnie ...
Kod :
static inline void ReplaceAll2(std::string &str, const std::string& from, const std::string& to)
{
// Same inner code...
// No return statement
}
Mam nadzieję, że będzie to pomocne dla niektórych innych ...
from
łańcuch jest pusty, w przeciwnym razie powstanie nieskończona pętla.
Wyobraź sobie duży binarny obiekt blob, w którym wszystkie bajty 0x00 zostaną zastąpione przez „\ 1 \ x30”, a wszystkie bajty 0x01 przez „\ 1 \ x31”, ponieważ protokół transportowy nie zezwala na bajty \ 0.
W przypadkach, gdy:
dostarczone rozwiązania nie mogą być zastosowane (ponieważ zastępują tylko pojedyncze znaki) lub mają problem z wydajnością, ponieważ wywoływałyby ciąg :: zamień kilka razy, co generuje kopie rozmiaru obiektu blob w kółko. (Nie znam rozwiązania wspomagającego, może z tej perspektywy jest OK)
To jeden spacery wzdłuż wszystkich zdarzeń w ciągu źródłowym i buduje nowy kawałek po kawałku ciąg raz :
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);
}
Proste wyszukiwanie i zamiana dla jednej postaci wyglądałoby mniej więcej tak:
s.replace(s.find("x"), 1, "y")
Aby to zrobić dla całego łańcucha, najłatwiej byłoby zapętlić, dopóki nie s.find
zaczniesz powracaćnpos
. Przypuszczam, że mógłbyś złapać również range_error
wyjście z pętli, ale to trochę brzydkie.
{
postać. Nie wiem, co to jest „podwójny aparat ortodontyczny”. Być może masz problem z czcionkami?
Jeśli chcesz zastąpić więcej niż jedną postać i masz do czynienia tylko z tym std::string
, ten fragment kodu będzie działał, zastępując sNeedle w sHaystack sReplace, a sNeedle i sReplace nie muszą być tego samego rozmiaru. Ta procedura wykorzystuje pętlę while do zastąpienia wszystkich wystąpień, a nie tylko pierwszego znalezionego od lewej do prawej.
while(sHaystack.find(sNeedle) != std::string::npos) {
sHaystack.replace(sHaystack.find(sNeedle),sNeedle.size(),sReplace);
}
find
dwa razy telefon. Zastanów się, czy ten wynik nie jest zmienną temp.
Jak sugerował Kirill, albo zastosuj metodę replace, albo iteruj wzdłuż łańcucha, zastępując każdy znak niezależnie.
Alternatywnie możesz użyć find
metody lub w find_first_of
zależności od tego, co musisz zrobić. Żadne z tych rozwiązań nie wykona zadania za jednym razem, ale z kilkoma dodatkowymi wierszami kodu powinieneś sprawić, by działały dla Ciebie. :-)
#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;
}
word
jest długi, może być dużo narzutu podczas wywoływania funkcji. Można zoptymalizować ten przekazując word
, target
i replacement
jako const odniesień.
Co z Abseil StrReplaceAll ? Z pliku nagłówka:
// This file defines `absl::StrReplaceAll()`, a general-purpose string
// replacement function designed for large, arbitrary text substitutions,
// especially on strings which you are receiving from some other system for
// further processing (e.g. processing regular expressions, escaping HTML
// entities, etc.). `StrReplaceAll` is designed to be efficient even when only
// one substitution is being performed, or when substitution is rare.
//
// If the string being modified is known at compile-time, and the substitutions
// vary, `absl::Substitute()` may be a better choice.
//
// Example:
//
// std::string html_escaped = absl::StrReplaceAll(user_input, {
// {"&", "&"},
// {"<", "<"},
// {">", ">"},
// {"\"", """},
// {"'", "'"}});
Stara szkoła :-)
std::string str = "H:/recursos/audio/youtube/libre/falta/";
for (int i = 0; i < str.size(); i++) {
if (str[i] == '/') {
str[i] = '\\';
}
}
std::cout << str;
Wynik:
H: \ recursos \ audio \ youtube \ libre \ falta \
To działa! Użyłem czegoś podobnego do tego w aplikacji księgarni, w której inwentarz był przechowywany w pliku CSV (np. Plik .dat). Ale w przypadku pojedynczego znaku, co oznacza, że zamiennik jest tylko jednym znakiem, np. „|”, Musi być w cudzysłowie „|” aby nie wyrzucić niepoprawnej stałej 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
Nietypowo używam obecnie CentOS, więc moja wersja kompilatora jest poniżej. Wersja C ++ (g ++), domyślnie 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.
Jeśli chcesz użyć std::string
s, możesz użyć funkcji tej przykładowej aplikacji bez strsub
zmian lub zaktualizować ją, jeśli chcesz, aby przyjmowała inny typ lub zestaw parametrów, aby osiągnąć mniej więcej ten sam cel. Zasadniczo używa właściwości i funkcjonalności, std::string
aby szybko usunąć dopasowany zestaw znaków i wstawić żądane znaki bezpośrednio w ciągu std::string
. Za każdym razem, gdy wykonuje tę operację zastępowania, offset jest aktualizowany, jeśli nadal może znaleźć pasujące znaki do zastąpienia, a jeśli nie może tego zrobić z powodu niczego więcej do zastąpienia, zwraca ciąg znaków w stanie z ostatniej aktualizacji.
#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;
}
Jeśli nie chcesz polegać na używaniu std::string
s jako parametrów, aby zamiast tego przekazywać ciągi w stylu C, możesz zobaczyć zaktualizowaną próbkę poniżej:
#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;
}
W prostych sytuacjach działa to całkiem dobrze bez użycia innej biblioteki niż std :: string (która jest już w użyciu).
Zamień wszystkie wystąpienia znaku a na znak b w some_string :
for (size_t i = 0; i < some_string.size(); ++i) {
if (some_string[i] == 'a') {
some_string.replace(i, 1, "b");
}
}
Jeśli ciąg jest duży lub wiele wezwań do zastąpienia jest problemem, możesz zastosować technikę wymienioną w tej odpowiedzi: https://stackoverflow.com/a/29752943/3622300
oto rozwiązanie, które rzuciłem, w maksymalnym duchu DRI. przeszuka sNeedle w sHaystack i zastąpi go sReplace, nTimes jeśli nie jest 0, w przeciwnym razie wszystkie wystąpienia sNeedle. nie będzie wyszukiwać ponownie w zastąpionym tekście.
std::string str_replace(
std::string sHaystack, std::string sNeedle, std::string sReplace,
size_t nTimes=0)
{
size_t found = 0, pos = 0, c = 0;
size_t len = sNeedle.size();
size_t replen = sReplace.size();
std::string input(sHaystack);
do {
found = input.find(sNeedle, pos);
if (found == std::string::npos) {
break;
}
input.replace(found, len, sReplace);
pos = found + replen;
++c;
} while(!nTimes || c < nTimes);
return input;
}
std::string
to pojemnik zaprojektowany specjalnie do pracy z sekwencjami znaków. link