Ich verwende derzeit den folgenden Code, um den gesamten std::strings
in meinen Programmen rechtszuschneiden:
std::string s;
s.erase(s.find_last_not_of(" \n\r\t")+1);
Es funktioniert gut, aber ich frage mich, ob es einige Endfälle gibt, bei denen es möglicherweise fehlschlägt.
Natürlich sind auch Antworten mit eleganten Alternativen und Linksanschlüssen möglich.
EDIT Seit c ++ 17 wurden einige Teile der Standardbibliothek entfernt. Glücklicherweise haben wir, beginnend mit c ++ 11, Lambdas, die eine überlegene Lösung darstellen.
#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(), [](int 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(), [](int 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;
}
Vielen Dank an https://stackoverflow.com/a/44973498/524503 , um die moderne Lösung aufzurufen.
Ich neige dazu, eine dieser 3 für meine Trimmbedürfnisse zu verwenden:
#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));
}
Sie sind ziemlich selbsterklärend und funktionieren sehr gut.
EDIT: Übrigens, ich habe std::ptr_fun
dabei, um std::isspace
zu unterscheiden, da es tatsächlich eine zweite Definition gibt, die Locales unterstützt. Das hätte auch eine Besetzung sein können, aber ich mag das lieber.
EDIT: Um einige Kommentare zum Akzeptieren eines Parameters durch Verweis ansprechen, ändern und zurückgeben. Genau. Eine Implementierung, die ich wahrscheinlich vorziehen würde, wäre zwei Funktionsgruppen, eine für die vorhandene und eine, die eine Kopie erstellt. Ein besserer Satz von Beispielen wäre:
#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;
}
Ich halte die ursprüngliche Antwort oben für den Kontext und im Interesse, die hoch gewählte Antwort weiterhin verfügbar zu halten.
Die Verwendung der Boost-String-Algorithmen wäre am einfachsten:
#include <boost/algorithm/string.hpp>
std::string str("hello world! ");
boost::trim_right(str);
str
ist jetzt "hello world!"
. Es gibt auch trim_left
und trim
, die beide Seiten beschneiden.
Wenn Sie einem der obigen Funktionsnamen _copy
-Suffix hinzufügen, z. trim_copy
, gibt die Funktion eine abgeschnittene Kopie der Zeichenfolge zurück, anstatt sie durch eine Referenz zu ändern.
Wenn Sie einem der obigen Funktionsnamen _if
-Suffix hinzufügen, z. trim_copy_if
, Sie können alle Zeichen, die Ihrem benutzerdefinierten Prädikat entsprechen, im Gegensatz zu Whitespaces trimmen.
Verwenden Sie den folgenden Code, um Leerzeichen und Tabulatorzeichen von std::strings
( ideone ) nach rechts zuzuschneiden:
// trim trailing spaces
size_t endpos = str.find_last_not_of(" \t");
size_t startpos = str.find_first_not_of(" \t");
if( std::string::npos != endpos )
{
str = str.substr( 0, endpos+1 );
str = str.substr( startpos );
}
else {
str.erase(std::remove(std::begin(str), std::end(str), ' '), std::end(str));
}
Und um das Ganze auszugleichen, füge ich auch den linken Trim-Code hinzu ( ideone ):
// trim leading spaces
size_t startpos = str.find_first_not_of(" \t");
if( string::npos != startpos )
{
str = str.substr( startpos );
}
Etwas spät zur Party, aber egal. Jetzt ist C++ 11 hier, wir haben Lambdas und Auto-Variablen. Meine Version, die auch Leerzeichen und leere Zeichenfolgen behandelt, lautet:
#include <cctype>
#include <string>
#include <algorithm>
inline std::string trim(const std::string &s)
{
auto wsfront=std::find_if_not(s.begin(),s.end(),[](int c){return std::isspace(c);});
auto wsback=std::find_if_not(s.rbegin(),s.rend(),[](int c){return std::isspace(c);}).base();
return (wsback<=wsfront ? std::string() : std::string(wsfront,wsback));
}
Wir könnten einen Reverse-Iterator aus wsfront
erstellen und als Abbruchbedingung im zweiten find_if_not
verwenden. Dies ist jedoch nur bei einer Whitespace-Zeichenfolge nützlich, und gcc 4.8 ist zumindest nicht schlau genug, um den Typ des Reverse-Objekts zu bestimmen Iterator (std::string::const_reverse_iterator
) mit auto
. Ich weiß nicht, wie teuer der Aufbau eines Reverse-Iterators ist, daher hier YMMV. Mit dieser Änderung sieht der Code folgendermaßen aus:
inline std::string trim(const std::string &s)
{
auto wsfront=std::find_if_not(s.begin(),s.end(),[](int c){return std::isspace(c);});
return std::string(wsfront,std::find_if_not(s.rbegin(),std::string::const_reverse_iterator(wsfront),[](int c){return std::isspace(c);}).base());
}
Was Sie tun, ist gut und robust. Ich habe die gleiche Methode schon lange verwendet und ich muss noch eine schnellere Methode finden:
const char* ws = " \t\n\r\f\v";
// trim from end of string (right)
inline std::string& rtrim(std::string& s, const char* t = ws)
{
s.erase(s.find_last_not_of(t) + 1);
return s;
}
// trim from beginning of string (left)
inline std::string& ltrim(std::string& s, const char* t = ws)
{
s.erase(0, s.find_first_not_of(t));
return s;
}
// trim from both ends of string (right then left)
inline std::string& trim(std::string& s, const char* t = ws)
{
return ltrim(rtrim(s, t), t);
}
Wenn Sie die zu beschneidenden Zeichen angeben, haben Sie die Flexibilität, Zeichen ohne Leerzeichen zu trimmen, und Sie können nur die Zeichen abschneiden, die Sie abschneiden möchten.
Probieren Sie das aus, es funktioniert für mich.
inline std::string trim(std::string& str)
{
str.erase(0, str.find_first_not_of(' ')); //prefixing spaces
str.erase(str.find_last_not_of(' ')+1); //surfixing spaces
return str;
}
Ich mag die Lösung von Tzaman, das einzige Problem dabei ist, dass keine Zeichenfolge getrimmt wird, die nur Leerzeichen enthält.
Um diesen Fehler zu korrigieren, fügen Sie zwischen den beiden Trimmerzeilen ein str.clear () ein
std::stringstream trimmer;
trimmer << str;
str.clear();
trimmer >> str;
std::string trim(const std::string &s)
{
std::string::const_iterator it = s.begin();
while (it != s.end() && isspace(*it))
it++;
std::string::const_reverse_iterator rit = s.rbegin();
while (rit.base() != it && isspace(*rit))
rit++;
return std::string(it, rit.base());
}
Im Falle einer leeren Zeichenfolge geht Ihr Code davon aus, dass das Hinzufügen von 1 zu string::npos
0 ergibt. string::npos
ist vom Typ string::size_type
, der unsigniert ist. Sie verlassen sich also auf das Überlaufverhalten der Addition.
Abgehackt von Cplusplus.com
std::string choppa(const std::string &t, const std::string &ws)
{
std::string str = t;
size_t found;
found = str.find_last_not_of(ws);
if (found != std::string::npos)
str.erase(found+1);
else
str.clear(); // str is all whitespace
return str;
}
Dies funktioniert auch für den Nullfall. :-)
Meine Lösung basiert auf der Antwort von @Bill the Lizard .
Beachten Sie, dass diese Funktionen die leere Zeichenfolge zurückgeben, wenn die Eingabezeichenfolge nur Leerzeichen enthält.
const std::string StringUtils::WHITESPACE = " \n\r\t";
std::string StringUtils::Trim(const std::string& s)
{
return TrimRight(TrimLeft(s));
}
std::string StringUtils::TrimLeft(const std::string& s)
{
size_t startpos = s.find_first_not_of(StringUtils::WHITESPACE);
return (startpos == std::string::npos) ? "" : s.substr(startpos);
}
std::string StringUtils::TrimRight(const std::string& s)
{
size_t endpos = s.find_last_not_of(StringUtils::WHITESPACE);
return (endpos == std::string::npos) ? "" : s.substr(0, endpos+1);
}
Meine Antwort ist eine Verbesserung der top answer für diesen Beitrag, die Steuerzeichen sowie Leerzeichen (0-32 und 127 in der ASCII - Tabelle ) trimmt.
std::isgraph
bestimmt, ob ein Zeichen eine grafische Darstellung hat. Sie können dies verwenden, um Evans Antwort zu ändern, um ein Zeichen zu entfernen, das keine grafische Darstellung von beiden Seiten einer Zeichenfolge hat. Das Ergebnis ist eine viel elegantere Lösung:
#include <algorithm>
#include <functional>
#include <string>
/**
* @brief Left Trim
*
* Trims whitespace from the left end of the provided std::string
*
* @param[out] s The std::string to trim
*
* @return The modified std::string&
*/
std::string& ltrim(std::string& s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(),
std::ptr_fun<int, int>(std::isgraph)));
return s;
}
/**
* @brief Right Trim
*
* Trims whitespace from the right end of the provided std::string
*
* @param[out] s The std::string to trim
*
* @return The modified std::string&
*/
std::string& rtrim(std::string& s) {
s.erase(std::find_if(s.rbegin(), s.rend(),
std::ptr_fun<int, int>(std::isgraph)).base(), s.end());
return s;
}
/**
* @brief Trim
*
* Trims whitespace from both ends of the provided std::string
*
* @param[out] s The std::string to trim
*
* @return The modified std::string&
*/
std::string& trim(std::string& s) {
return ltrim(rtrim(s));
}
Hinweis: Alternativ können Sie std::iswgraph
verwenden, wenn Sie Unterstützung für breite Zeichen benötigen. Sie müssen diesen Code jedoch auch bearbeiten, um die std::wstring
-Manipulation zu aktivieren. Dies ist etwas, das ich nicht getestet habe ( Weitere Informationen zu dieser Option finden Sie auf der Referenzseite für std::basic_string
.
Das ist was ich benutze. Entfernen Sie einfach den Platz von vorne, und tun Sie, wenn noch etwas übrig ist, dasselbe von hinten.
void trim(string& s) {
while(s.compare(0,1," ")==0)
s.erase(s.begin()); // remove leading whitespaces
while(s.size()>0 && s.compare(s.size()-1,1," ")==0)
s.erase(s.end()-1); // remove trailing whitespaces
}
Für das, was es wert ist, ist hier eine schlanke Implementierung mit Blick auf die Leistung. Es ist viel schneller als bei vielen anderen Trimmroutinen, die ich je gesehen habe. Anstelle von Iteratoren und std :: finds werden rohe Strings und Indizes verwendet. Es optimiert die folgenden Sonderfälle: Größe 0 Zeichenfolge (nichts tun), Zeichenfolge ohne Leerzeichen (nichts tun), Zeichenfolge mit nur nachlaufendem Leerzeichen (nur Größe ändern), Zeichenfolge, die ausschließlich Leerzeichen ist (Zeichenfolge löschen) . Und im schlimmsten Fall (Zeichenfolge mit führendem Whitespace) ist es am besten, einen effizienten Kopieraufbau durchzuführen, indem nur eine Kopie ausgeführt wird und diese Kopie anstelle der ursprünglichen Zeichenfolge verschoben wird.
void TrimString(std::string & str)
{
if(str.empty())
return;
const auto pStr = str.c_str();
size_t front = 0;
while(front < str.length() && std::isspace(int(pStr[front]))) {++front;}
size_t back = str.length();
while(back > front && std::isspace(int(pStr[back-1]))) {--back;}
if(0 == front)
{
if(back < str.length())
{
str.resize(back - front);
}
}
else if(back <= front)
{
str.clear();
}
else
{
str = std::move(std::string(str.begin()+front, str.begin()+back));
}
}
s.erase(0, s.find_first_not_of(" \n\r\t"));
s.erase(s.find_last_not_of(" \n\r\t")+1);
Mit C++ 11 kam auch ein regular expression -Modul, mit dem sich führende oder nachgestellte Leerzeichen trimmen lassen.
Vielleicht so etwas:
std::string ltrim(const std::string& s)
{
static const std::regex lws{"^[[:space:]]*", std::regex_constants::extended};
return std::regex_replace(s, lws, "");
}
std::string rtrim(const std::string& s)
{
static const std::regex tws{"[[:space:]]*$", std::regex_constants::extended};
return std::regex_replace(s, tws, "");
}
std::string trim(const std::string& s)
{
return ltrim(rtrim(s));
}
Eine elegante Art, dies zu tun, kann wie sein
std::string & trim(std::string & str)
{
return ltrim(rtrim(str));
}
Und die unterstützenden Funktionen sind implementiert als:
std::string & ltrim(std::string & str)
{
auto it = std::find_if( str.begin() , str.end() , [](char ch){ return !std::isspace<char>(ch , std::locale::classic() ) ; } );
str.erase( str.begin() , it);
return str;
}
std::string & rtrim(std::string & str)
{
auto it = std::find_if( str.rbegin() , str.rend() , [](char ch){ return !std::isspace<char>(ch , std::locale::classic() ) ; } );
str.erase( it.base() , str.end() );
return str;
}
Und wenn Sie all diese Voraussetzungen erfüllt haben, können Sie auch Folgendes schreiben:
std::string trim_copy(std::string const & str)
{
auto s = str;
return ltrim(rtrim(s));
}
C++ 11-Implementierung anpassen:
static void trim(std::string &s) {
s.erase(s.begin(), std::find_if_not(s.begin(), s.end(), [](char c){ return std::isspace(c); }));
s.erase(std::find_if_not(s.rbegin(), s.rend(), [](char c){ return std::isspace(c); }).base(), s.end());
}
Ich denke, wenn Sie nach dem "besten Weg" fragen, um eine Zeichenkette zu trimmen, würde ich sagen, dass eine gute Implementierung die folgende wäre:
Offensichtlich gibt es zu viele verschiedene Ansätze, und dies hängt definitiv davon ab, was Sie tatsächlich brauchen. Die C-Standardbibliothek enthält jedoch noch einige sehr nützliche Funktionen in <string.h>, z. B. memchr. Es gibt einen Grund, warum C immer noch als die beste Sprache für IO angesehen wird - seine Standardlib ist reine Effizienz.
inline const char* trim_start(const char* str)
{
while (memchr(" \t\n\r", *str, 4)) ++str;
return str;
}
inline const char* trim_end(const char* end)
{
while (memchr(" \t\n\r", end[-1], 4)) --end;
return end;
}
inline std::string trim(const char* buffer, int len) // trim a buffer (input?)
{
return std::string(trim_start(buffer), trim_end(buffer + len));
}
inline void trim_inplace(std::string& str)
{
str.assign(trim_start(str.c_str()),
trim_end(str.c_str() + str.length()));
}
int main()
{
char str [] = "\t \nhello\r \t \n";
string trimmed = trim(str, strlen(str));
cout << "'" << trimmed << "'" << endl;
system("pause");
return 0;
}
Mein Beitrag zum Lärm. trim
verwendet standardmäßig einen neuen String und gibt den geänderten String zurück, während trim_in_place
den an ihn übergebenen String ändert. Die Funktion trim
unterstützt die Verschiebungssemantik von C++ 11.
#include <string>
// modifies input string, returns input
std::string& trim_left_in_place(std::string& str) {
size_t i = 0;
while(i < str.size() && isspace(str[i])) { ++i; };
return str.erase(0, i);
}
std::string& trim_right_in_place(std::string& str) {
size_t i = str.size();
while(i > 0 && isspace(str[i - 1])) { --i; };
return str.erase(i, str.size());
}
std::string& trim_in_place(std::string& str) {
return trim_left_in_place(trim_right_in_place(str));
}
// returns newly created strings
std::string trim_right(std::string str) {
return trim_right_in_place(str);
}
std::string trim_left(std::string str) {
return trim_left_in_place(str);
}
std::string trim(std::string str) {
return trim_left_in_place(trim_right_in_place(str));
}
#include <cassert>
int main() {
std::string s1(" \t\r\n ");
std::string s2(" \r\nc");
std::string s3("c \t");
std::string s4(" \rc ");
assert(trim(s1) == "");
assert(trim(s2) == "c");
assert(trim(s3) == "c");
assert(trim(s4) == "c");
assert(s1 == " \t\r\n ");
assert(s2 == " \r\nc");
assert(s3 == "c \t");
assert(s4 == " \rc ");
assert(trim_in_place(s1) == "");
assert(trim_in_place(s2) == "c");
assert(trim_in_place(s3) == "c");
assert(trim_in_place(s4) == "c");
assert(s1 == "");
assert(s2 == "c");
assert(s3 == "c");
assert(s4 == "c");
}
Ich bin mir nicht sicher, ob Ihre Umgebung dieselbe ist, aber bei meiner leeren Zeichenfolge wird das Programm abgebrochen. Ich würde diesen Löschaufruf entweder mit einem if (! S.empty ()) umwickeln oder Boost wie bereits erwähnt verwenden.
Folgendes habe ich mir ausgedacht:
std::stringstream trimmer;
trimmer << str;
trimmer >> str;
Durch die Stream-Extraktion werden Whitespaces automatisch eliminiert, sodass dies wie ein Zauber wirkt.
Ziemlich sauber und auch elegant, wenn ich es selbst sage. ;)
Dies kann in C++ 11 durch Hinzufügen von back()
und pop_back()
einfacher gemacht werden.
while ( !s.empty() && isspace(s.back()) ) s.pop_back();
Hier ist meine Version:
size_t beg = s.find_first_not_of(" \r\n");
return (beg == string::npos) ? "" : in.substr(beg, s.find_last_not_of(" \r\n") - beg);
Die oben genannten Methoden sind großartig, aber manchmal möchten Sie eine Kombination von Funktionen verwenden, die Ihrer Routine als Leerzeichen dienen. In diesem Fall kann die Verwendung von Funktoren zum Kombinieren von Operationen unübersichtlich werden. Daher bevorzuge ich eine einfache Schleife, die ich für das Zuschneiden modifizieren kann. Hier ist eine leicht modifizierte Trimmfunktion, die von der C-Version hier auf SO kopiert wurde. In diesem Beispiel schneide ich nicht alphanumerische Zeichen.
string trim(char const *str)
{
// Trim leading non-letters
while(!isalnum(*str)) str++;
// Trim trailing non-letters
end = str + strlen(str) - 1;
while(end > str && !isalnum(*end)) end--;
return string(str, end+1);
}
In dieser Version werden interne Leerzeichen und nicht alphanumerische Zeichen abgeschnitten:
static inline std::string &trimAll(std::string &s)
{
if(s.size() == 0)
{
return s;
}
int val = 0;
for (int cur = 0; cur < s.size(); cur++)
{
if(s[cur] != ' ' && std::isalnum(s[cur]))
{
s[val] = s[cur];
val++;
}
}
s.resize(val);
return s;
}
Noch eine weitere Option - entfernt ein oder mehrere Zeichen von beiden Enden.
string strip(const string& s, const string& chars=" ") {
size_t begin = 0;
size_t end = s.size()-1;
for(; begin < s.size(); begin++)
if(chars.find_first_of(s[begin]) == string::npos)
break;
for(; end > begin; end--)
if(chars.find_first_of(s[end]) == string::npos)
break;
return s.substr(begin, end-begin+1);
}
Hier ist eine leicht verständliche Lösung für Anfänger, die nicht daran gewöhnt sind, std::
überall zu schreiben, und die const
- Korrektheit, iterator
s, STL algorithm
s usw. noch nicht kennt.
#include <string>
#include <cctype> // for isspace
using namespace std;
// Left trim the given string (" hello! " --> "hello! ")
string left_trim(string str) {
int numStartSpaces = 0;
for (int i = 0; i < str.length(); i++) {
if (!isspace(str[i])) break;
numStartSpaces++;
}
return str.substr(numStartSpaces);
}
// Right trim the given string (" hello! " --> " hello!")
string right_trim(string str) {
int numEndSpaces = 0;
for (int i = str.length() - 1; i >= 0; i--) {
if (!isspace(str[i])) break;
numEndSpaces++;
}
return str.substr(0, str.length() - numEndSpaces);
}
// Left and right trim the given string (" hello! " --> "hello!")
string trim(string str) {
return right_trim(left_trim(str));
}
Ich hoffe es hilft...
Da ich meine alte C++ - Trim-Funktion mit einem C++ 11-Ansatz aktualisieren wollte, habe ich viele der veröffentlichten Antworten auf die Frage getestet. Meine Schlussfolgerung ist, dass ich meine alte C++ - Lösung beibehalten habe!
Es ist das größte Einzelstück, sogar das Hinzufügen weiterer Zeichen zur Überprüfung (z. B.\r\n Ich sehe keinen Anwendungsfall für\f\v) ist immer noch schneller als Lösungen, die einen Algorithmus verwenden.
std::string & trimMe (std::string & str)
{
// right trim
while (str.length () > 0 && (str [str.length ()-1] == ' ' || str [str.length ()-1] == '\t'))
str.erase (str.length ()-1, 1);
// left trim
while (str.length () > 0 && (str [0] == ' ' || str [0] == '\t'))
str.erase (0, 1);
return str;
}
Was ist mit diesem ...?
#include <iostream>
#include <string>
#include <regex>
std::string ltrim( std::string str ) {
return std::regex_replace( str, std::regex("^\\s+"), std::string("") );
}
std::string rtrim( std::string str ) {
return std::regex_replace( str, std::regex("\\s+$"), std::string("") );
}
std::string trim( std::string str ) {
return ltrim( rtrim( str ) );
}
int main() {
std::string str = " \t this is a test string \n ";
std::cout << "-" << trim( str ) << "-\n";
return 0;
}
Hinweis: Ich bin noch relativ neu in C++, also verzeihen Sie mir bitte, wenn ich nicht hier bin.
Hier ist eine einfache Implementierung. Für eine solche einfache Operation sollten Sie wahrscheinlich keine speziellen Konstrukte verwenden. Die eingebaute isspace () - Funktion kümmert sich um verschiedene Formen weißer Zeichen, daher sollten wir diese nutzen. Sie müssen auch Sonderfälle berücksichtigen, bei denen die Zeichenfolge leer ist oder nur ein paar Leerzeichen. Links oder rechts trimmen könnte aus dem folgenden Code abgeleitet werden.
string trimSpace(const string &str) {
if (str.empty()) return str;
string::size_type i,j;
i=0;
while (i<str.size() && isspace(str[i])) ++i;
if (i == str.size())
return string(); // empty string
j = str.size() - 1;
//while (j>0 && isspace(str[j])) --j; // the j>0 check is not needed
while (isspace(str[j])) --j
return str.substr(i, j-i+1);
}
Mit C++ 17 können Sie basic_string_view :: remove_prefix und basic_string_view :: remove_suffix :
std::string_view trim(std::string_view s) const
{
s.remove_prefix(std::min(s.find_first_not_of(" \t\r\v\n"), s.size()));
s.remove_suffix((s.size() - 1) - std::min(s.find_last_not_of(" \t\r\v\n"), s.size() - 1));
return s;
}
Ich weiß, dass dies eine sehr alte Frage ist, aber ich habe ein paar Codezeilen zu Ihren hinzugefügt, und der Leerraum wird an beiden Enden abgeschnitten.
void trim(std::string &line){
auto val = line.find_last_not_of(" \n\r\t") + 1;
if(val == line.size() || val == std::string::npos){
val = line.find_first_not_of(" \n\r\t");
line = line.substr(val);
}
else
line.erase(val);
}
c ++ 11:
int i{};
string s = " h e ll \t\n o";
string trim = " \n\t";
while ((i = s.find_first_of(trim)) != -1)
s.erase(i,1);
cout << s;
ausgabe:
hello
funktioniert auch mit leeren Saiten
Unten ist eine Lösung mit einem Durchgang (möglicherweise zwei Durchgänge). Er geht zweimal über die Leerzeichen der Zeichenkette und einmal über die Leerzeichen hinaus.
void trim(std::string& s) {
if (s.empty())
return;
int l = 0, r = s.size() - 1;
while (l < s.size() && std::isspace(s[l++])); // l points to first non-whitespace char.
while (r >= 0 && std::isspace(s[r--])); // r points to last non-whitespace char.
if (l > r)
s = "";
else {
l--;
r++;
int wi = 0;
while (l <= r)
s[wi++] = s[l++];
s.erase(wi);
}
return;
}
Ist das gut? (Weil dieser Beitrag absolut eine andere Antwort braucht :)
string trimBegin(string str)
{
string whites = "\t\r\n ";
int i = 0;
while (whites.find(str[i++]) != whites::npos);
str.erase(0, i);
return str;
}
Ähnlich verhält es sich mit dem trimEnd nur um die Polaritätsindizes.
Ich verwende dieses:
void trim(string &str){
int i=0;
//left trim
while (isspace(str[i])!=0)
i++;
str = str.substr(i,str.length()-i);
//right trim
i=str.length()-1;
while (isspace(str[i])!=0)
i--;
str = str.substr(0,i+1);
}
std::string trim( std::string && str )
{
size_t end = str.find_last_not_of( " \n\r\t" );
if ( end != std::string::npos )
str.resize( end + 1 );
size_t start = str.find_first_not_of( " \n\r\t" );
if ( start != std::string::npos )
str = str.substr( start );
return std::move( str );
}