Você está bagunçando um pouco a memória aqui com todas as chamadas para "substituir": a complexidade seria n² se você remover "o" de "ooooooo ... o". Acho que dá para fazer melhor, mas essa solução tem o mérito de ser fácil de entender.
Zonko,
1
Por que este não é um loop for real, em vez de um loop for ofuscado?
Shirik de
Estou acostumado a aplicar o princípio da "menor surpresa". Os loops For são para uso de incremento de índice simples, na maioria das vezes. Aqui, na minha opinião, um loop while é mais claro.
yves Baumes
1
@aldo Como regra geral, é melhor evitar a complexidade e, por exemplo, usar regex como mencionado em outras respostas. Mas, dependendo da sua necessidade, você pode querer controlar as dependências do projeto. Um pequeno trecho de código que faz exatamente o que você precisa, nada mais, às vezes é melhor.
yves Baumes
158
#include<boost/algorithm/string.hpp>// include Boost, a C++ library...
std::string target("Would you like a foo of chocolate. Two foos of chocolate?");
boost::replace_all(target,"foo","bar");
Observe que você não tem que criar explicitamente std :: string's para o padrão e substituição: boost :: replace_all (target, "foo", "bar");
Alexis Wilke
4
+1, com uma ressalva: replace_allserá o segfault para versões de boost> 1,43 no Sun Studio para qualquer versão <12.3
Brian Vandenberg
3
boostaumenta o tempo de compilação consideravelmente em dispositivos embarcados. Mesmo quad core ARMv7. 100 linhas de código compiladas em 2 minutos, sem aumento, 2 segundos.
Piotr Kula
4
@ppumkin: isso significa que seu compilador (ou configuração de compilação, ou qualquer outra coisa) é uma droga, não a arquitetura alvo, que não tem nada a ver com isso.
Daniel Kamil Kozar
Se o seu compilador suportar cabeçalho pré-compilado, é altamente recomendável usá-lo ao usar o boost. Isso realmente economiza tempo.
Alexey Omelchenko
33
No C ++ 11, você pode fazer isso em uma linha com uma chamada para regex_replace:
#include<string>#include<regex>using std::string;
string do_replace( string const& in, string const& from, string const& to ){return std::regex_replace( in, std::regex(from), to );}
string test ="Remove all spaces";
std::cout << do_replace(test," ","")<< std::endl;
Observe também que frompode ser uma expressão regular - portanto, você pode usar critérios de correspondência mais sofisticados, se necessário. O que não vejo é como fazer isso sem aplicar alguma forma de análise de expressão regular - em vez de usar apenas uma interpretação direta dos fromcaracteres.
Brent Bradburn
Isso pode exigir um compilador atualizado. Funcionou com o gcc 5.0, mas tive alguns problemas com o gcc 4.8.4.
Brent Bradburn
@nobar, sim, se bem me lembro o suporte regex em 4.8.x não estava completo. Além disso, você pode ter pesquisas mais sofisticadas, mas será penalizado com o tempo ... Vai ser mais lento do que as outras funções de pesquisa e substituição mais simples.
Alexis Wilke
2
Observe que isso funcionará apenas para caracteres alfanuméricos básicos e nada mais sem fazer muito pré-processamento, dependendo do tipo de string. Eu não encontrei uma substituição de string baseada em regex de propósito geral ainda.
Tentei este exemplo no GCC, mas não compilou - ele não gostou do uso de T :: size_t. Substituir T :: size_t por typename T :: size_type corrige o problema.
Andrew Wyatt
3
A maneira mais fácil (oferecendo algo próximo ao que você escreveu) é usar Boost.Regex , especificamente regex_replace .
std :: string incorporou os métodos find () e replace (), mas eles são mais complicados de trabalhar, pois exigem lidar com índices e comprimentos de string.
Existem também os algoritmos de sequência de impulso, incluindo replace_all (regex pode ser um pouco pesado para essa substituição simples).
UncleBens
3
Eu acredito que isso funcionaria. Leva const char * 's como parâmetro.
//params find and replace cannot be NULLvoidFindAndReplace( std::string& source,constchar* find,constchar* replace ){//ASSERT(find != NULL);//ASSERT(replace != NULL);size_t findLen = strlen(find);size_t replaceLen = strlen(replace);size_t pos =0;//search for the next occurrence of find within sourcewhile((pos = source.find(find, pos))!= std::string::npos){//replace the found string with the replacement
source.replace( pos, findLen, replace );//the next line keeps you from searching your replace string, //so your could replace "hello" with "hello world" //and not have it blow chunks.
pos += replaceLen;}}
Dado que size_typepara uma string é unsigned, sua >=verificação na condição de loop sempre será true. Você tem que usar std::string::nposlá.
Pavel Minaev
size_type não é sem sinal. Não tem assinatura em muitas plataformas, mas não em todas.
Alan,
12
Por que diabos isso não faz parte de std :: string? Existe alguma outra classe String séria no mundo da programação que não oferece uma operação de 'localizar e substituir'? Certamente é mais comum do que ter dois iteradores e querer substituir o texto entre eles ?? Às vezes, std :: string parece um carro com um pára-brisa de espectro ajustável, mas nenhuma maneira de abrir a janela do motorista.
Spike0xff
@ Spike0xff boost hasroll_down_window
ta.speot.is
1
@gustafr: Erro meu. Trabalhei em sistemas onde compiladores mais antigos definiram size_t incorretamente.
Alan
1
// Replace all occurrences of searchStr in str with replacer// Each match is replaced only once to prevent an infinite loop// The algorithm iterates once over the input and only concatenates // to the output, so it should be reasonably efficient
std::string replace(const std::string& str,const std::string& searchStr,const std::string& replacer){// Prevent an infinite loop if the input is emptyif(searchStr ==""){return str;}
std::string result ="";size_t pos =0;size_t pos2 = str.find(searchStr, pos);while(pos2 != std::string::npos){
result += str.substr(pos, pos2-pos)+ replacer;
pos = pos2 + searchStr.length();
pos2 = str.find(searchStr, pos);}
result += str.substr(pos, str.length()-pos);return result;}
Precisamos apenas procurar por novas correspondências da última correspondência, é por isso que o algoritmo rastreia cuidadosamente a última correspondência na pos. pos2 sempre armazena a próxima correspondência, então concatenamos a string entre pos e pos2 para o resultado, então avançamos pos e pos2. Se nenhuma outra correspondência puder ser encontrada, concatenamos o restante da string para resultar.
Respostas:
Por que não implementar seu próprio substituto?
fonte
Aqui está a documentação oficial sobre replace_all.
fonte
replace_all
será o segfault para versões de boost> 1,43 no Sun Studio para qualquer versão <12.3boost
aumenta o tempo de compilação consideravelmente em dispositivos embarcados. Mesmo quad core ARMv7. 100 linhas de código compiladas em 2 minutos, sem aumento, 2 segundos.No C ++ 11, você pode fazer isso em uma linha com uma chamada para
regex_replace
:resultado:
fonte
from
pode ser uma expressão regular - portanto, você pode usar critérios de correspondência mais sofisticados, se necessário. O que não vejo é como fazer isso sem aplicar alguma forma de análise de expressão regular - em vez de usar apenas uma interpretação direta dosfrom
caracteres.Por que não retornar uma string modificada?
Se você precisa de desempenho, aqui está uma função otimizada que modifica a string de entrada, mas não cria uma cópia da string:
Testes:
Resultado:
fonte
Meu modelo de localizar e substituir no local embutido:
Ele retorna uma contagem do número de itens substituídos (para uso se você deseja executá-lo sucessivamente, etc). Para usá-lo:
fonte
A maneira mais fácil (oferecendo algo próximo ao que você escreveu) é usar Boost.Regex , especificamente regex_replace .
std :: string incorporou os métodos find () e replace (), mas eles são mais complicados de trabalhar, pois exigem lidar com índices e comprimentos de string.
fonte
Eu acredito que isso funcionaria. Leva const char * 's como parâmetro.
fonte
size_type
para uma string éunsigned
, sua>=
verificação na condição de loop sempre serátrue
. Você tem que usarstd::string::npos
lá.roll_down_window
fonte
A verificação de oldStr estar vazia é importante. Se por algum motivo esse parâmetro estiver vazio, você ficará preso em um loop infinito.
Mas sim, use o C ++ 11 experimentado e testado ou a solução Boost, se puder.
fonte