EDIT Depuis c++17, certaines parties de la bibliothèque standard ont été supprimées. Heureusement, à partir de c++11, nous avons des lambdas qui sont une solution supérieure.
#include <algorithm>
#include <cctype>
#include <locale>
// trim from start (in place)
static inline void ltrim(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
return !std::isspace(ch);
}));
}
// trim from end (in place)
static inline void rtrim(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
return !std::isspace(ch);
}).base(), s.end());
}
// trim from both ends (in place)
static inline void trim(std::string &s) {
ltrim(s);
rtrim(s);
}
// trim from start (copying)
static inline std::string ltrim_copy(std::string s) {
ltrim(s);
return s;
}
// trim from end (copying)
static inline std::string rtrim_copy(std::string s) {
rtrim(s);
return s;
}
// trim from both ends (copying)
static inline std::string trim_copy(std::string s) {
trim(s);
return s;
}
Merci à https://stackoverflow.com/a/44973498/524503 pour avoir proposé une solution moderne.
Réponse originale :
J'ai tendance à utiliser l'un de ces 3 modèles pour mes besoins en matière de coupe :
#include <algorithm>
#include <functional>
#include <cctype>
#include <locale>
// trim from start
static inline std::string <rim(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(),
std::not1(std::ptr_fun<int, int>(std::isspace))));
return s;
}
// trim from end
static inline std::string &rtrim(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(),
std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
return s;
}
// trim from both ends
static inline std::string &trim(std::string &s) {
return ltrim(rtrim(s));
}
Ils sont assez explicites et fonctionnent très bien.
EDIT : BTW, j'ai std::ptr_fun
pour aider à désambiguïser std::isspace
parce qu'il y a en fait une deuxième définition qui supporte les locales. Cela aurait pu être un casting tout de même, mais j'ai tendance à préférer ceci.
EDIT : Pour répondre à certains commentaires concernant l'acceptation d'un paramètre par référence, sa modification et son renvoi. Je suis d'accord. Une implémentation que je préférerais probablement serait deux ensembles de fonctions, un pour in place et un qui fait une copie. Un meilleur ensemble d'exemples serait :
#include <algorithm>
#include <functional>
#include <cctype>
#include <locale>
// trim from start (in place)
static inline void ltrim(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(),
std::not1(std::ptr_fun<int, int>(std::isspace))));
}
// trim from end (in place)
static inline void rtrim(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(),
std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
}
// trim from both ends (in place)
static inline void trim(std::string &s) {
ltrim(s);
rtrim(s);
}
// trim from start (copying)
static inline std::string ltrim_copy(std::string s) {
ltrim(s);
return s;
}
// trim from end (copying)
static inline std::string rtrim_copy(std::string s) {
rtrim(s);
return s;
}
// trim from both ends (copying)
static inline std::string trim_copy(std::string s) {
trim(s);
return s;
}
Je garde cependant la réponse originale ci-dessus pour le contexte et dans l'intérêt de garder la réponse la plus votée toujours disponible.
610 votes
Les réponses à cette question témoignent des lacunes de la bibliothèque standard C++.
89 votes
@IdanK Et il n'y a toujours pas cette fonction dans C++11.
45 votes
@IdanK : Super, n'est-ce pas ! Regardez toutes les options concurrentes que nous avons maintenant à notre disposition, sans être encombrés par l'idée qu'une seule personne se fait de la " le site la manière dont nous devons le faire" !
10 votes
@LightnessRacesinOrbit : Avoir des fonctions pratiques dans la bibliothèque n'empêche pas d'être incapable de faire les choses autrement. La bibliothèque a
vector
mais nous ne sommes pas obligés d'utiliser uniquement le vecteur.5 votes
@MooingDuck : Le choix des types est une chose, le choix des fonctionnalités est une autre sur un type donné en est une autre, puisque fournir ces choix peut créer des limitations sur le reste du type et sur son implémentation.
65 votes
@LightnessRacesinOrbit fonctionnalité au sein d'un type, eh bien, c'est une décision de conception, et l'ajout d'une fonction trim à une chaîne de caractères pourrait (au moins sous c++) ne pas être la meilleure solution de toute façon - mais ne pas fournir une façon standard de le faire, au lieu de laisser tout le monde se tracasser sur les mêmes petits problèmes encore et encore, n'aide certainement pas non plus.
2 votes
Je ne sais vraiment pas de quoi vous parlez. Il y a est une façon standard de faire ces choses en C++ : en incluant la bibliothèque spécialisée de votre choix et en utilisant son ainsi que toutes les autres fonctions spécialisées dans le domaine de votre problème.
8 votes
@DevSolar, il n'y a pas de standard de le faire, parce que la chaîne std::string de l'application standard bibliothèque ("std" signifie standard FYI) ne le fournit pas. Vous devez utiliser une bibliothèque tierce.
4 votes
@MilanBabuškov : Des langages comme Java ou C# essaient de fournir des bibliothèques "tout ce qui chante, tout ce qui danse" comme faisant partie du langage proprement dit. Les langages comme C ou C++ ne fournissent que les bases les plus élémentaires, et laissent aux spécialistes le soin de trouver des solutions adaptées au domaine. C'est leur approche "standard". Il se trouve que je suis le responsable d'une bibliothèque C++ propriétaire qui permet de tokeniser, découper, analyser, comparer et dédupliquer des adresses internationales, et je peux vous dire, après avoir
trim()
surstd::
ne m'aurait pas épargné de travail puisque le domaine de mon problème m'obligeait à travailler avec des données très peu fiables.std::
/STL en premier lieu.32 votes
Vous pouvez vous demander pourquoi les fonctions de rognage ne sont pas intégrées dans le système de gestion de l'environnement.
std::string
alors que ce sont des fonctions comme celles-ci qui rendent d'autres langages si agréables à utiliser (Python par exemple).5 votes
@IdanK, au moins un gourou influent du C++ pense qu'il y a déjà trop dans la classe standard des chaînes de caractères. Je ne suis pas sûr d'être d'accord, mais c'est une lecture intéressante : gotw.ca/gotw/084.htm
3 votes
@MarkRansom, Oui, il y a des arguments pour lesquels il ne devrait pas l'être. sur la classe string, mais cela pourrait être une fonction libre, comme std::trim(...), tout comme dans boost.
4 votes
Il y a trop de ce que Stepanov pensait devoir être dans la STL pour la rendre générique par rapport à la STL, et pas assez de ce que la STL devrait être. besoins d'être en STL pour le rendre utile ; un exemple de déconnexion dans la compréhension et ce qui se passe quand quelque chose est conçu sur la base de la théorie plutôt que des exigences. (mais je l'utilise quand même tout le temps :)
20 votes
Pas de problème, je vais écrire ma propre version 1.000.000ème. En utilisant un
trimmable
et de l'envelopper dans une demi-douzaine de couches de jolis modèles génériques, de sorte que vous puissiez également découper des singes et des girafes (éventuellement à la place et/ou à l'aide d'un allocateur personnalisé) sans pratiquement aucune surcharge de codage et avec des optimisations rapides comme l'éclair.0 votes
1. Quelque chose comme Boost devrait être une nouvelle STL. 2. Le C++ devrait avoir des pragmes de compilation conditionnelle (comme weak, mais intégré au compilateur). Et alors, le C++ serait enfin capable de rivaliser, à nouveau, sur un pied d'égalité avec les autres langages en termes de facilité d'utilisation ET de portabilité.
4 votes
Découpage à gauche :
s = s.substr(s.find_first_not_of(" "));
22 votes
Il me semble que la réponse en une seule ligne fournie par l'auteur de la question bat la plupart, sinon la totalité, des réponses élaborées fournies ci-dessous.
1 votes
Il y a une chose qui m'irrite à propos du C++, même si j'en ai acquis la maîtrise. Si l'importation d'autres bibliothèques pour des niveaux d'abstraction plus élevés est attendue, pourquoi la norme ne spécifie-t-elle pas les modules ? Il m'a fallu 6 ans pour surmonter les nombreux obstacles et enfin compiler, lier et inclure des bibliothèques externes sans me fier aux guides de démarrage rapide (souvent périmés).
1 votes
Pour tous ceux qui évoluent dans le monde .Net, voici un bon article d'évaluation comparative sur les moyens les plus rapides de couper des chaînes de caractères : Le moyen le plus rapide de découper des chaînes de caractères en C# .Net
0 votes
Longue vie à Java, l'API est la meilleure.
7 votes
Ce type de question montre à la fois le meilleur et le pire du C++.
4 votes
Toujours pas de support de ltrim et rtrim en c++17 !
1 votes
J'ai commencé à coder avec C++ en 2014. Je suis passé à JS, Java et PHP peu de temps après. En revenant au C++ 5 ans plus tard, il est décevant de voir à quel point la bibliothèque standard s'est peu améliorée.
1 votes
Quelqu'un sait-il pourquoi le c++ a ces problèmes de base ? En comparaison avec c#, le travail avec les chaînes en c++ est incroyablement pauvre. Je ne peux pas croire qu'en c++ tout le monde doive écrire sa propre fonction pour les chaînes de caractères Trim, TrimStart, TrimEnd, Split, Join, .....
1 votes
@bmi QtCore est une bonne alternative à la bibliothèque standard, pour les chaînes, les conteneurs, etc. Le bon côté est que Qt a tout son écosystème de bibliothèques, le mauvais côté est qu'is t n'est pas le standard (réduit la compatibilité). La bibliothèque standard implémente des concepts de très bas niveau et est conçue de manière maladroite.