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.
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.
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.
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());
Pourquoi ne pas utiliser une expression régulière:
boost::regex_replace(str, boost::regex("[' ']{2,}"), " ");
que diriez-vous de isspace(lhs) && isspace(rhs)
pour gérer tous les types d'espaces