it-swarm.com.de

Was ist der beste Weg, um std :: string zu trimmen?

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.

696
Milan Babuškov

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.

Ursprüngliche Antwort:

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 &ltrim(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.

568
Evan Teran

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.

391
Leon Timmermans

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 );
}
58
Bill the Lizard

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());
}
51
David G

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.

38
Galik

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

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

http://ideone.com/nFVtEo

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());
}
19
Pushkoff

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.

15
Greg Hewgill

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. :-)

14
Paul Nathan

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);
}
10
DavidRR

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 .

9
Clay Freeman

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

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));
    }
}
7
mbgda
s.erase(0, s.find_first_not_of(" \n\r\t"));                                                                                               
s.erase(s.find_last_not_of(" \n\r\t")+1);   
7
freeboy1015

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));
}
6
gjha

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());
}
5
GutiMac

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:

  1. Ordnet temporäre Zeichenfolgen nicht zu
  2. Verfügt über Überlastungen für das In-Place-Trimmen und das Kopieren von Kopien
  3. Kann leicht angepasst werden, um verschiedene Validierungssequenzen/-logiken zu akzeptieren

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;
}
4
Jorma Rebane

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");  
}
3
vmrob

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. 

3
Steve

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

3
tzaman

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

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);
3
nulleight

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);
}
2
Corwin Joy

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

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);
}
1
Brian W.

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, iterators, STL algorithms 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...

1
cute_ptr

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

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.

1
Duncan

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);
}
1
Kemin Zhou

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

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);
}
0
user3229557

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

0
user1438233

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

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.

0
Bondolin

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);
}
0
Floella
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 );
}
0