Remover espaços de std :: string em C ++

222

Qual é a maneira preferida de remover espaços de uma seqüência de caracteres em C ++? Eu poderia percorrer todos os personagens e criar uma nova string, mas existe uma maneira melhor?

Steve Hanov
fonte

Respostas:

257

A melhor coisa a fazer é usar o algoritmo remove_ife o isspace:

remove_if(str.begin(), str.end(), isspace);

Agora, o próprio algoritmo não pode alterar o contêiner (apenas modificar os valores); portanto, embaralha os valores e retorna um ponteiro para onde o final agora deve estar. Portanto, precisamos chamar string :: erase para modificar o comprimento do contêiner:

str.erase(remove_if(str.begin(), str.end(), isspace), str.end());

Também devemos observar que remove_if fará no máximo uma cópia dos dados. Aqui está uma implementação de exemplo:

template<typename T, typename P>
T remove_if(T beg, T end, P pred)
{
    T dest = beg;
    for (T itr = beg;itr != end; ++itr)
        if (!pred(*itr))
            *(dest++) = *itr;
    return dest;
}
Matt Price
fonte
54
Como 'isspace' tem sobrecargas, você provavelmente precisará qualificar o código genérico para usar :: isspace (a implementação C que não usa um código de idioma) ou ser recebido com erros de instanciação de modelo enigmático.
Bklyn
4
Tudo - tenha cuidado com o método acima (as duas linhas únicas, não a versão do modelo, embora possa ter o mesmo problema). Eu usei em um projeto sem perceber que nem sempre é correto. Por exemplo, se você passar a string "1 + 1", ela retornará "1 + 11". Mudei para o método do @rupello abaixo e funcionou bem neste caso. Feliz codificação!
21412 JoeB
6
@ Joe A resposta menciona explicitamente que você precisa ligar erasedepois. Isso retornará o resultado correto.
precisa saber é o seguinte
31
-1 esse uso de isspaceé UB para todos os conjuntos de caracteres, exceto o ASCII original de 7 bits. C99 §7.4 / 1. isso não surpreende -me que ele tenha sido upvoted da ordem de 71 votos por agora, apesar de ser muito maus conselhos.
Saúde e hth. #: 25412 Alf
16
Apenas para repetir, o código nesta resposta passa valores negativos (diferentes de EOF) para isspace, para todos os caracteres não ASCII, com a opção padrão prática de assinatura para char. Assim, tem um comportamento indefinido . Estou repetindo porque suspeito de uma tentativa deliberada de afogar esse fato no barulho.
Saúde e hth. - Alf
100
std::string::iterator end_pos = std::remove(str.begin(), str.end(), ' ');
str.erase(end_pos, str.end());
Arno
fonte
31
Meu voto positivo para a linguagem canônica apagar / remover. Pode ser transformado em um único liner: str.erase (std :: remove (str.begin (), str.end (), ''), str.end ());
Bklyn
11
Nota: Você precisa incluir <algorithm>para que isso funcione.
TaraJul
37

De gamedev

string.erase(std::remove_if(string.begin(), string.end(), std::isspace), string.end());
rupello
fonte
22
Isso não será compilado em implementações em conformidade com os padrões devido às sobrecargas de localização de std :: isspace. Você precisará usar :: isspace ou executar algumas maquinações ilegíveis com std :: bind2nd. O código genérico não é bonito?
Bklyn
Observe também que, se algum dos caracteres for negativo (por exemplo, um caractere UTF8 quando o caractere for assinado), o uso de ::isspaceé UB.
Martin Bonner apoia Monica
30

Você pode usar o Boost String Algo? http://www.boost.org/doc/libs/1_35_0/doc/html/string_algo/usage.html#id1290573

erase_all(str, " "); 
Nemanja Trifunovic
fonte
3
É mais lento do que o remove_if(str.begin(), str.end(), isspace);mencionado por Matt Price. Não sei porque. Na verdade, todas as coisas de impulso, que têm alternativas STL, são mais lentas que as correspondentes do gcc (todas as que testei). Alguns deles são imensamente mais lentos! (até 5 vezes em inserções unordered_map) Talvez seja por causa do cache da CPU do ambiente compartilhado ou algo parecido.
21312 Etherealone
16

Para aparar, use algoritmos de seqüência de impulso :

#include <boost/algorithm/string.hpp>

using namespace std;
using namespace boost;

// ...

string str1(" hello world! ");
trim(str1);      // str1 == "hello world!"
romano
fonte
15

Você pode usar esta solução para remover um caractere:

#include <algorithm>
#include <string>
using namespace std;

str.erase(remove(str.begin(), str.end(), char_to_remove), str.end());
user2281802
fonte
1
# include <string.h> using namespace std;
Slackmart
Esta solução está correta para mim. O primeiro não é.
Jason Liu
1
o uso do namespace std deve ser evitado. stackoverflow.com/questions/1452721/…
infinitezero
12

Oi, você pode fazer algo assim. Esta função exclui todos os espaços.

string delSpaces(string &str) 
{
   str.erase(std::remove(str.begin(), str.end(), ' '), str.end());
   return str;
}

Eu criei outra função, que exclui todos os espaços desnecessários.

string delUnnecessary(string &str)
{
    int size = str.length();
    for(int j = 0; j<=size; j++)
    {
        for(int i = 0; i <=j; i++)
        {
            if(str[i] == ' ' && str[i+1] == ' ')
            {
                str.erase(str.begin() + i);
            }
            else if(str[0]== ' ')
            {
                str.erase(str.begin());
            }
            else if(str[i] == '\0' && str[i-1]== ' ')
            {
                str.erase(str.end() - 1);
            }
        }
    }
    return str;
}
ddacot
fonte
8
string replaceinString(std::string str, std::string tofind, std::string toreplace)
{
        size_t position = 0;
        for ( position = str.find(tofind); position != std::string::npos; position = str.find(tofind,position) )
        {
                str.replace(position ,1, toreplace);
        }
        return(str);
}

use-o:

string replace = replaceinString(thisstring, " ", "%20");
string replace2 = replaceinString(thisstring, " ", "-");
string replace3 = replaceinString(thisstring, " ", "+");
SudoBash
fonte
7

Se você quiser fazer isso com uma macro fácil, aqui está uma:

#define REMOVE_SPACES(x) x.erase(std::remove(x.begin(), x.end(), ' '), x.end())

Isso pressupõe que você tenha feito, é #include <string>claro.

Chame assim:

std::string sName = " Example Name ";
REMOVE_SPACES(sName);
printf("%s",sName.c_str()); // requires #include <stdio.h>
Volomike
fonte
5
por que você usaria uma macro para isso?
Dani
1
Menos digitação no teclado para uma tarefa comum.
Volomike
3
Igualmente curto para o site de chamada é chamar uma função que leva uma referência lvalue a uma string. As macros podem ter comportamentos surpreendentes interagindo com seus argumentos (especialmente com efeitos colaterais), mas, pior ainda, se estiverem envolvidos em um erro, seus nomes não aparecerão nas mensagens do compilador, sua implementação sim.
Chris Uzdavinis
2

Usei o trabalho abaixo por muito tempo - não tenho certeza sobre sua complexidade.

s.erase(std::unique(s.begin(),s.end(),[](char s,char f){return (f==' '||s==' ');}),s.end());

quando você deseja remover caracteres ' 'e alguns, por exemplo, - use

s.erase(std::unique(s.begin(),s.end(),[](char s,char f){return ((f==' '||s==' ')||(f=='-'||s=='-'));}),s.end());

Da mesma forma, apenas aumente ||se o número de caracteres que você deseja remover não for 1

mas, como mencionado por outros, o idioma apagar e remover também parece bom.

RaGa__M
fonte
1
string removeSpaces(string word) {
    string newWord;
    for (int i = 0; i < word.length(); i++) {
        if (word[i] != ' ') {
            newWord += word[i];
        }
    }

    return newWord;
}

Esse código basicamente pega uma string e interage com todos os caracteres nela. Em seguida, verifica se essa sequência é um espaço em branco; caso contrário, o caractere é adicionado a uma nova sequência.

Maçãs Crocantes
fonte
1
   #include <algorithm>
   using namespace std;

   int main() {
       .
       .
       s.erase( remove( s.begin(), s.end(), ' ' ), s.end() );
       .
       .
   }

Fonte:

Referência retirada deste fórum.

John
fonte
1
Isso realmente não adiciona nada além do que essa resposta já faz. Há mais explicações ou detalhes que você poderia adicionar para tornar sua resposta mais alta qualidade e vale a pena manter nessa questão?
Das_Geek 26/11/19
Eu acho que é mais simples , porque faz a mesma coisa em uma declaração.
John John
2
Ótimo! Em seguida, coloque esse raciocínio como uma explicação diretamente na sua resposta . A pergunta original tem mais de onze anos e, sem uma justificativa, sua resposta pode ser vista como ruído quando comparada às outras respostas aceitas e bem votadas. Ter essa explicação ajudará a impedir que sua resposta seja removida.
Das_Geek 26/11/19
Isso seria bom, mas não consegui entender como devo colocar isso na minha resposta ... que minha resposta é melhor do que esta resposta . ? Seria um grande prazer se você pudesse editar minha resposta.
John John
2
Infelizmente, editar sua resposta para adicionar esse conteúdo seria contrário às diretrizes de edição , e minha edição provavelmente seria recusada ou revertida mais tarde. Você pode usar o primeiro link neste comentário para editar a resposta. É totalmente aceitável afirmar que você acha que sua resposta é melhor que outra e fornecer justificativa para isso. A comunidade decidirá se você está certo com a votação positiva ou negativa.
26519 Das_Geek
0

No C ++ 20, você pode usar a função livre std :: erase

std::string str = " Hello World  !";
std::erase(str, ' ');

Exemplo completo:

#include<string>
#include<iostream>

int main() {
    std::string str = " Hello World  !";
    std::erase(str, ' ');
    std::cout << "|" << str <<"|";
}

Eu imprimo | de modo que é óbvio que o espaço no início também é removido.

nota: isso remove apenas o espaço, e não todos os outros caracteres possíveis que podem ser considerados espaços em branco, consulte https://en.cppreference.com/w/cpp/string/byte/isspace

NoSenseEtAl
fonte
0

Remove todos os caracteres de espaço em branco , como guias e quebras de linha (C ++ 11):

string str = " \n AB cd \t efg\v\n";
str = regex_replace(str,regex("\\s"),"");
AnselmRu
fonte
Por que você recomendaria essa abordagem à resposta aceita pela @ Matt-Price de mais de uma década atrás?
Jeremy Caney
Que todas as soluções sejam apresentadas aqui. Talvez alguém precise dessa solução.
AnselmRu
Eu não estou argumentando contra isso. Estou dizendo para facilitar as pessoas avaliarem abordagens diferentes, explicando as diferenças e para quais cenários elas podem ser mais adequadas.
Jeremy Caney
1
Provavelmente, essa solução não é a mais econômica, mas permite que você se livre de todos os caracteres de espaço em branco '\ s', não apenas de espaços ''.
AnselmRu
0
  string str = "2C F4 32 3C B9 DE";
  str.erase(remove(str.begin(),str.end(),' '),str.end());
  cout << str << endl;

saída: 2CF4323CB9DE

Kerim FIRAT
fonte
-1
string removespace(string str)
{    
    int m = str.length();
    int i=0;
    while(i<m)
    {
        while(str[i] == 32)
        str.erase(i,1);
        i++;
    }    
}
teste c
fonte
3
Geralmente, é preferível que você adicione uma breve explicação para codificar respostas.
Arcyqwerty
1
@test - length()retorna a size_t, não uma int. erase()leva um size_type, não um int. A função provavelmente falhará se dois espaços consecutivos forem encontrados, pois o índice é sempre incrementado. Se um espaço for removido, o loop lerá além dos limites da string. Você provavelmente deve excluir esta resposta, pois precisa de muita ajuda.
JWW
-3

Receio que seja a melhor solução em que consigo pensar. Mas você pode usar reserve () para pré-alocar previamente a memória mínima necessária para acelerar um pouco as coisas. Você terminará com uma nova sequência que provavelmente será mais curta, mas ocupará a mesma quantidade de memória, mas evitará realocações.

EDIT: Dependendo da sua situação, isso pode resultar em menos sobrecarga do que personagens confusos.

Você deve tentar abordagens diferentes e ver o que é melhor para você: talvez você não tenha nenhum problema de desempenho.

Dave Van den Eynde
fonte
remove_if faz no máximo uma cópia de cada valor. Portanto, realmente não há muita sobrecarga em relação ao que precisa ser feito.
Matt Price