web-dev-qa-db-fra.com

Remplacer plusieurs espaces par un espace dans une chaîne

Comment pourrais-je faire quelque chose dans c++ semblable au code suivant:

//Lang: Java
string.replaceAll("  ", " ");

Cet extrait de code remplacerait tous les espaces multiples d'une chaîne par un seul espace.

21
evenodd
bool BothAreSpaces(char lhs, char rhs) { return (lhs == rhs) && (lhs == ' '); }

std::string::iterator new_end = std::unique(str.begin(), str.end(), BothAreSpaces);
str.erase(new_end, str.end());   

Comment ça marche Le std::unique a deux formes. Le premier formulaire traverse une plage et supprime les doublons adjacents. Donc, la chaîne "abbaaabbbb" devient "abab". La seconde forme, que j’ai utilisée, prend un prédicat qui doit prendre deux éléments et retourner la valeur true s’ils doivent être considérés comme des doublons. La fonction que j'ai écrite, BothAreSpaces, sert cet objectif. Il détermine exactement ce que son nom implique, que ses deux paramètres sont des espaces. Ainsi, lorsque combiné avec std::unique, les espaces adjacents en double sont supprimés.

Tout comme std::remove et remove_if , std::unique ne rend pas le conteneur plus petit, il déplace simplement les éléments à la fin plus près du début. Il renvoie un itérateur à la nouvelle fin de plage afin que vous puissiez l'utiliser pour appeler la fonction erase , qui est une fonction membre de la classe string.

En le décomposant, la fonction effacement prend deux paramètres, un itérateur de début et de fin, pour une plage à effacer. Pour son premier paramètre, je passe la valeur de retour de std::unique, car c’est là que je veux commencer à effacer. Pour son deuxième paramètre, je passe l'itérateur de fin de la chaîne.

62
Benjamin Lindley

Alors, j’ai essayé avec les expressions std :: remove_if & lambda - bien qu’il me semble toujours plus facile à suivre que le code ci-dessus, il n’a pas ce mot "wow neat, je ne savais pas que vous pouviez le faire" En tout cas, je l’affiche encore, ne serait-ce que pour apprendre:

bool prev(false);
char rem(' ');
auto iter = std::remove_if(str.begin(), str.end(), [&] (char c) -> bool {
    if (c == rem && prev) {
        return true;
    }
    prev = (c == rem);
    return false;
});
in.erase(iter, in.end());

EDITréalise que std :: remove_if retourne un itérateur utilisable .. supprime le code inutile.

4
paul23

Une variante de la réponse de Benjamin Lindley qui utilise une expression lambda pour rendre les choses plus propres:

std::string::iterator new_end = 
        std::unique(str.begin(), str.end(),
        [=](char lhs, char rhs){ return (lhs == rhs) && (lhs == ' '); }
        );
str.erase(new_end, str.end());
3
tlaxcala

Pourquoi ne pas utiliser une expression régulière:

boost::regex_replace(str, boost::regex("[' ']{2,}"), " ");

1
Mike Jiang

que diriez-vous de isspace(lhs) && isspace(rhs) pour gérer tous les types d'espaces

0
Patrick Neary