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?

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;
}

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());

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());

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, " "); 

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



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;
}

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, " ", "+");

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>

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.


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.


1
   #include <algorithm>
   using namespace std;

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

Fonte:

Referência retirada deste fórum.


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


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"),"");

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


-1
string removespace(string str)
{    
    int m = str.length();
    int i=0;
    while(i<m)
    {
        while(str[i] == 32)
        str.erase(i,1);
        i++;
    }    
}

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.


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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.