Entfernen von führenden und nachfolgenden Leerzeichen aus einer Zeichenfolge

88

So entfernen Sie Leerzeichen aus einem Zeichenfolgenobjekt in C ++.
Beispiel: Entfernen von führenden und nachfolgenden Leerzeichen aus dem folgenden Zeichenfolgenobjekt.

//Original string: "         This is a sample string                    "
//Desired string: "This is a sample string"

Die Zeichenfolgenklasse bietet meines Wissens keine Methoden zum Entfernen von führenden und nachfolgenden Leerzeichen.

Um das Problem zu erweitern, können Sie diese Formatierung erweitern, um zusätzliche Leerzeichen zwischen den Wörtern der Zeichenfolge zu verarbeiten. Beispielsweise,

// Original string: "          This       is         a sample   string    " 
// Desired string:  "This is a sample string"  

Mit den in der Lösung genannten String-Methoden kann ich mir vorstellen, diese Operationen in zwei Schritten auszuführen.

  1. Entfernen Sie führende und nachfolgende Leerzeichen.
  2. Verwenden Sie find_first_of, find_last_of, find_first_not_of, find_last_not_of und substr wiederholt an Wortgrenzen, um die gewünschte Formatierung zu erhalten.
Ankur
quelle

Antworten:

127

Dies wird als Trimmen bezeichnet. Wenn Sie Boost verwenden können , würde ich es empfehlen.

Verwenden Sie andernfalls, find_first_not_ofum den Index des ersten Nicht-Leerzeichens abzurufen und dann find_last_not_ofden Index vom Ende abzurufen, das kein Leerzeichen ist. Verwenden Sie diese Option substr, um die Unterzeichenfolge ohne umgebende Leerzeichen abzurufen.

Als Antwort auf Ihre Bearbeitung kenne ich den Begriff nicht, aber ich würde etwas in der Art von "Reduzieren" erraten, also habe ich es so genannt. :) (Hinweis, ich habe den Leerraum aus Gründen der Flexibilität als Parameter geändert.)

#include <iostream>
#include <string>

std::string trim(const std::string& str,
                 const std::string& whitespace = " \t")
{
    const auto strBegin = str.find_first_not_of(whitespace);
    if (strBegin == std::string::npos)
        return ""; // no content

    const auto strEnd = str.find_last_not_of(whitespace);
    const auto strRange = strEnd - strBegin + 1;

    return str.substr(strBegin, strRange);
}

std::string reduce(const std::string& str,
                   const std::string& fill = " ",
                   const std::string& whitespace = " \t")
{
    // trim first
    auto result = trim(str, whitespace);

    // replace sub ranges
    auto beginSpace = result.find_first_of(whitespace);
    while (beginSpace != std::string::npos)
    {
        const auto endSpace = result.find_first_not_of(whitespace, beginSpace);
        const auto range = endSpace - beginSpace;

        result.replace(beginSpace, range, fill);

        const auto newStart = beginSpace + fill.length();
        beginSpace = result.find_first_of(whitespace, newStart);
    }

    return result;
}

int main(void)
{
    const std::string foo = "    too much\t   \tspace\t\t\t  ";
    const std::string bar = "one\ntwo";

    std::cout << "[" << trim(foo) << "]" << std::endl;
    std::cout << "[" << reduce(foo) << "]" << std::endl;
    std::cout << "[" << reduce(foo, "-") << "]" << std::endl;

    std::cout << "[" << trim(bar) << "]" << std::endl;
}

Ergebnis:

[too much               space]  
[too much space]  
[too-much-space]  
[one  
two]  
GManNickG
quelle
Ich nehme an, Sie meinten 'size_t'. und Sie haben ein Off-by-One auf dem Teilstring, sollte substr sein (beginStr, endStr - beginStr + 1);
GoldPseudo
Sollte site_tsein size_t? Und ich denke, wo Sie den Kommentar haben, no whitespacebedeutet, dass die Zeichenfolge nur Leerzeichen oder leer ist.
Fred Larson
Danke, habe den size_tTippfehler und das Off-by-One in der Bearbeitung behoben , aber nicht bemerkt, dass mein Kommentar invertiert wurde, danke.
GManNickG
@GMan sehr elegante Lösung. Vielen Dank.
Ankur
Fehler: Versuchen Sie, "one \ ttwo" durch trim () auszuführen. Ergebnis ist eine leere Zeichenfolge. Sie müssen endStr auch gegen std :: string :: npos testen.
Dlchambers
48

Einfaches Entfernen von führenden, nachfolgenden und zusätzlichen Leerzeichen aus einem std :: string in einer Zeile

value = std::regex_replace(value, std::regex("^ +| +$|( ) +"), "$1");

nur führende Leerzeichen entfernen

value.erase(value.begin(), std::find_if(value.begin(), value.end(), std::bind1st(std::not_equal_to<char>(), ' ')));

oder

value = std::regex_replace(value, std::regex("^ +"), "");

Entfernen Sie nur nachgestellte Leerzeichen

value.erase(std::find_if(value.rbegin(), value.rend(), std::bind1st(std::not_equal_to<char>(), ' ')).base(), value.end());

oder

value = std::regex_replace(value, std::regex(" +$"), "");

nur zusätzliche Leerzeichen entfernen

value = regex_replace(value, std::regex(" +"), " ");
Evgeny Karpov
quelle
3
Schön. Es wäre nützlich, einige Informationen darüber bereitzustellen, was hier passiert, da es schwierig ist, diese Codes zu verstehen.
Marcin
Funktioniert jedoch nur in C ++ 11.
Martin Pecka
7
Tabs werden nicht entfernt, dies kann jedoch behoben werden. Was nicht behoben werden kann, ist, dass es furchtbar langsam ist (~ 100-mal langsamer als Antworten mit substroder erase).
4LegsDrivenCat
Für die Geschwindigkeitsoptimierung ist Regex nicht die optimale Lösung, aber es könnte verbessert werden, indem einmal eine Instanz von Regex erstellt wird
Evgeny Karpov,
40

Ich benutze derzeit diese Funktionen:

// trim from left
inline std::string& ltrim(std::string& s, const char* t = " \t\n\r\f\v")
{
    s.erase(0, s.find_first_not_of(t));
    return s;
}

// trim from right
inline std::string& rtrim(std::string& s, const char* t = " \t\n\r\f\v")
{
    s.erase(s.find_last_not_of(t) + 1);
    return s;
}

// trim from left & right
inline std::string& trim(std::string& s, const char* t = " \t\n\r\f\v")
{
    return ltrim(rtrim(s, t), t);
}

// copying versions

inline std::string ltrim_copy(std::string s, const char* t = " \t\n\r\f\v")
{
    return ltrim(s, t);
}

inline std::string rtrim_copy(std::string s, const char* t = " \t\n\r\f\v")
{
    return rtrim(s, t);
}

inline std::string trim_copy(std::string s, const char* t = " \t\n\r\f\v")
{
    return trim(s, t);
}
Galik
quelle
21

Boost String Trim Algorithmus

#include <boost/algorithm/string/trim.hpp>

[...]

std::string msg = "   some text  with spaces  ";
boost::algorithm::trim(msg);
Jon-Hanson
quelle
8

Dies ist meine Lösung zum Entfernen der führenden und nachfolgenden Bereiche ...

std::string stripString = "  Plamen     ";
while(!stripString.empty() && std::isspace(*stripString.begin()))
    stripString.erase(stripString.begin());

while(!stripString.empty() && std::isspace(*stripString.rbegin()))
    stripString.erase(stripString.length()-1);

Das Ergebnis ist "Plamen"

Plamen Stoyanov
quelle
8

So können Sie es machen:

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 it2 =  std::find_if( str.begin() , str.end() , [](char ch){ return !std::isspace<char>(ch , std::locale::classic() ) ; } );
  str.erase( str.begin() , it2);
  return str;   
}

std::string & rtrim(std::string & str)
{
  auto it1 =  std::find_if( str.rbegin() , str.rend() , [](char ch){ return !std::isspace<char>(ch , std::locale::classic() ) ; } );
  str.erase( it1.base() , str.end() );
  return str;   
}

Und wenn Sie alle diese Funktionen eingerichtet haben, können Sie auch Folgendes schreiben:

std::string trim_copy(std::string const & str)
{
   auto s = str;
   return ltrim(rtrim(s));
}

Versuche dies

jha-G
quelle
7

Beispiel für das Trimmen von führenden und nachfolgenden Leerzeichen gemäß Jon-Hansons Vorschlag, Boost zu verwenden (entfernt nur nachfolgende und ausstehende Leerzeichen):

#include <boost/algorithm/string/trim.hpp>

std::string str = "   t e s t    ";

boost::algorithm::trim ( str );

Ergebnisse in "t e s t"

Es gibt auch

  • trim_left führt zu "t e s t "
  • trim_right führt zu " t e s t"
Semjon Mössinger
quelle
5
/// strip a string, remove leading and trailing spaces
void strip(const string& in, string& out)
{
    string::const_iterator b = in.begin(), e = in.end();

    // skipping leading spaces
    while (isSpace(*b)){
        ++b;
    }

    if (b != e){
        // skipping trailing spaces
        while (isSpace(*(e-1))){
            --e;
        }
    }

    out.assign(b, e);
}

Im obigen Code ist die Funktion isSpace () eine boolesche Funktion, die angibt, ob ein Zeichen ein Leerzeichen ist. Sie können diese Funktion implementieren, um Ihre Anforderungen widerzuspiegeln, oder einfach isspace () von "ctype.h" aufrufen, wenn Sie möchten .

Murphy78
quelle
3

Die Verwendung der Standardbibliothek hat viele Vorteile, aber man muss sich einiger Sonderfälle bewusst sein, die Ausnahmen verursachen. Beispielsweise deckte keine der Antworten den Fall ab, in dem eine C ++ - Zeichenfolge einige Unicode-Zeichen enthält. In diesem Fall, wenn Sie die Funktion isspace verwenden eine Ausnahme ausgelöst .

Ich habe den folgenden Code zum Trimmen der Zeichenfolgen und einiger anderer Operationen verwendet, die nützlich sein könnten. Die Hauptvorteile dieses Codes sind: Er ist sehr schnell (schneller als jeder Code, den ich jemals getestet habe), verwendet nur die Standardbibliothek und verursacht niemals eine Ausnahme:

#include <string>
#include <algorithm>
#include <functional>
#include <locale>
#include <iostream>

typedef unsigned char BYTE;

std::string strTrim(std::string s, char option = 0)
{
    // convert all whitespace characters to a standard space
    std::replace_if(s.begin(), s.end(), (std::function<int(BYTE)>)::isspace, ' ');

    // remove leading and trailing spaces
    size_t f = s.find_first_not_of(' ');
    if (f == std::string::npos) return "";
    s = s.substr(f, s.find_last_not_of(' ') - f + 1);

    // remove consecutive spaces
    s = std::string(s.begin(), std::unique(s.begin(), s.end(),
        [](BYTE l, BYTE r){ return l == ' ' && r == ' '; }));

    switch (option)
    {
    case 'l':  // convert to lowercase
        std::transform(s.begin(), s.end(), s.begin(), ::tolower);
        return s;
    case 'U':  // convert to uppercase
        std::transform(s.begin(), s.end(), s.begin(), ::toupper);
        return s;
    case 'n':  // remove all spaces
        s.erase(std::remove(s.begin(), s.end(), ' '), s.end());
        return s;
    default: // just trim
        return s;
    }
}
Polfosol ఠ_ఠ
quelle
3

Beispiel zum Trimmen von führenden und nachfolgenden Leerzeichen

std::string aString("    This is a string to be trimmed   ");
auto start = aString.find_first_not_of(' ');
auto end = aString.find_last_not_of(' ');
std::string trimmedString;
trimmedString = aString.substr(start, (end - start) + 1);

ODER

trimmedSring = aString.substr(aString.find_first_not_of(' '), (aString.find_last_not_of(' ') - aString.find_first_not_of(' ')) + 1);
Thinkal VB
quelle
3
Menschen werden es nicht mögen, in 10 Seiten Code zu schauen, um zu lernen, wie man einen String schneidet.
Thinkal VB
2
Es ist kaputt, wenn die Zeichenfolge nur Leerzeichen enthält
DAG
2

Ich habe das getestet, alles funktioniert. Diese Methode processInput fordert den Benutzer lediglich auf, etwas einzugeben. Sie gibt eine Zeichenfolge zurück, die weder intern zusätzliche Leerzeichen noch zusätzliche Leerzeichen am Anfang oder am Ende enthält. Hoffe das hilft. (Geben Sie auch eine Menge Kommentare ein, um das Verständnis zu vereinfachen.)

Sie können sehen, wie Sie es in main () unten implementieren

#include <string>
#include <iostream>

string processInput() {
  char inputChar[256];
  string output = "";
  int outputLength = 0;
  bool space = false;
  // user inputs a string.. well a char array
  cin.getline(inputChar,256);
  output = inputChar;
       string outputToLower = "";
  // put characters to lower and reduce spaces
  for(int i = 0; i < output.length(); i++){
    // if it's caps put it to lowercase
    output[i] = tolower(output[i]);
    // make sure we do not include tabs or line returns or weird symbol for null entry array thingy
    if (output[i] != '\t' && output[i] != '\n' && output[i] != 'Ì') {
      if (space) {
        // if the previous space was a space but this one is not, then space now is false and add char
        if (output[i] != ' ') {
          space = false;
          // add the char
          outputToLower+=output[i];
        }
      } else {
        // if space is false, make it true if the char is a space
        if (output[i] == ' ') {
          space = true;
        }
        // add the char
        outputToLower+=output[i];
      }
    }
  }
  // trim leading and tailing space
  string trimmedOutput = "";
  for(int i = 0; i < outputToLower.length(); i++){
    // if it's the last character and it's not a space, then add it
    // if it's the first character and it's not a space, then add it
    // if it's not the first or the last then add it
    if (i == outputToLower.length() - 1 && outputToLower[i] != ' ' || 
      i == 0 && outputToLower[i] != ' ' || 
      i > 0 && i < outputToLower.length() - 1) {
      trimmedOutput += outputToLower[i];
    } 
  }
  // return
  output = trimmedOutput;
  return output;
}

int main() {
  cout << "Username: ";
  string userName = processInput();
  cout << "\nModified Input = " << userName << endl;
}
Elipsis
quelle
2

Dies könnte die einfachste von allen sein.

Sie können Leerzeichen von beiden Seiten verwenden string::findund string::rfindfinden und die Zeichenfolge reduzieren.

void TrimWord(std::string& word)
{
    if (word.empty()) return;

    // Trim spaces from left side
    while (word.find(" ") == 0)
    {
        word.erase(0, 1);
    }

    // Trim spaces from right side
    size_t len = word.size();
    while (word.rfind(" ") == --len)
    {
        word.erase(len, len + 1);
    }
}
user2983960
quelle
2

Warum komplizieren?

std::string removeSpaces(std::string x){
    if(x[0] == ' '){ x.erase(0, 1); }
    if(x[x.length()-1] == ' '){ x.erase(x.length()-1, x.length()); }
    return x;
}

Dies funktioniert auch dann, wenn der Boost fehlschlagen sollte, kein regulärer Ausdruck, keine seltsamen Dinge oder Bibliotheken.

Jack Of Blades
quelle
0
    char *str = (char*) malloc(50 * sizeof(char));
    strcpy(str, "    some random string (<50 chars)  ");

    while(*str == ' ' || *str == '\t' || *str == '\n')
            str++;

    int len = strlen(str);

    while(len >= 0 && 
            (str[len - 1] == ' ' || str[len - 1] == '\t' || *str == '\n')
    {
            *(str + len - 1) = '\0';
            len--;
    }

    printf(":%s:\n", str);
Amarghosh
quelle
0
void removeSpaces(string& str)
{
    /* remove multiple spaces */
    int k=0;
    for (int j=0; j<str.size(); ++j)
    {
            if ( (str[j] != ' ') || (str[j] == ' ' && str[j+1] != ' ' ))
            {
                    str [k] = str [j];
                    ++k;
            }

    }
    str.resize(k);

    /* remove space at the end */   
    if (str [k-1] == ' ')
            str.erase(str.end()-1);
    /* remove space at the begin */
    if (str [0] == ' ')
            str.erase(str.begin());
}
Devesh Agrawal
quelle
0
string trim(const string & sStr)
{
    int nSize = sStr.size();
    int nSPos = 0, nEPos = 1, i;
    for(i = 0; i< nSize; ++i) {
        if( !isspace( sStr[i] ) ) {
            nSPos = i ;
            break;
        }
    }
    for(i = nSize -1 ; i >= 0 ; --i) {
        if( !isspace( sStr[i] ) ) {
            nEPos = i;
            break;
        }
    }
    return string(sStr, nSPos, nEPos - nSPos + 1);
}
kjk
quelle
0

Wie wäre es mit: für führende und nachfolgende Räume:

string string_trim(const string& in) {

    stringstream ss;
    string out;
    ss << in;
    ss >> out;
    return out;

}

Oder für einen Satz:

string trim_words(const string& sentence) {
    stringstream ss;
    ss << sentence;
    string s;
    string out;

    while(ss >> s) {

        out+=(s+' ');
    }
    return out.substr(0, out.length()-1);
}
Iderwok
quelle
0

ordentlich und sauber

 void trimLeftTrailingSpaces(string &input) {
        input.erase(input.begin(), find_if(input.begin(), input.end(), [](int ch) {
            return !isspace(ch);
        }));
    }

    void trimRightTrailingSpaces(string &input) {
        input.erase(find_if(input.rbegin(), input.rend(), [](int ch) {
            return !isspace(ch);
        }).base(), input.end());
    }
user1856722
quelle
0

Nein boost, nein regex, nur die stringBibliothek. So einfach ist das.

string trim(const string s) { // removes whitespace characters from beginnig and end of string s
    const int l = (int)s.length();
    int a=0, b=l-1;
    char c;
    while(a<l && ((c=s.at(a))==' '||c=='\t'||c=='\n'||c=='\v'||c=='\f'||c=='\r'||c=='\0')) a++;
    while(b>a && ((c=s.at(b))==' '||c=='\t'||c=='\n'||c=='\v'||c=='\f'||c=='\r'||c=='\0')) b--;
    return s.substr(a, 1+b-a);
}
ProjectPhysX
quelle
1
... und Sie haben es vermieden, 2 Millionen Header-Dateien in Ihren Build einzubringen!
Larry_C
0

In C ++ 17 std::basic_string_viewwurde eine Klassenvorlage eingeführt , die sich auf eine konstante zusammenhängende Folge von char-ähnlichen Objekten bezieht, dh auf eine Ansicht der Zeichenfolge. Abgesehen davon, dass es eine sehr ähnliche Oberfläche hat, std::basic_stringverfügt es über zwei zusätzliche Funktionen: remove_prefix()Die Ansicht wird verkleinert, indem der Start nach vorne verschoben wird. und remove_suffix(), wodurch die Ansicht verkleinert wird, indem das Ende nach hinten verschoben wird. Diese können verwendet werden, um den vorderen und hinteren Raum zu verkleinern:

#include <string_view>
#include <string>

std::string_view ltrim(std::string_view str)
{
    const auto pos(str.find_first_not_of(" "));
    str.remove_prefix(pos);
    return str;
}

std::string_view rtrim(std::string_view str)
{
    const auto pos(str.find_last_not_of(" "));
    str.remove_suffix(str.length() - pos - 1);
    return str;
}

std::string_view trim(std::string_view str)
{
    str = ltrim(str);
    str = rtrim(str);
    return str;
}

int main()
{
    std::string str = "   hello world   ";
    auto sv1{ ltrim(str) };  // "hello world   "
    auto sv2{ rtrim(str) };  // "   hello world"
    auto sv3{ trim(str) };   // "hello world"

    //If you want, you can create std::string objects from std::string_view objects
    auto s1{ sv1 };
    auto s2{ sv2 };
    auto s3{ sv3 };
}

Hinweis: Das std::string_viewist keine Referenz, daher ist es nur gültig, solange die ursprüngliche Zeichenfolge noch vorhanden ist.

Jignatius
quelle
-1

Was ist mit der Lösch-Entfernungs-Sprache ?

std::string s("...");
s.erase( std::remove(s.begin(), s.end(), ' '), s.end() );

Es tut uns leid. Ich habe zu spät gesehen, dass Sie nicht alle Leerzeichen entfernen möchten .

vt.
quelle
-1

Meine Lösung für dieses Problem, bei dem keine STL-Methoden, sondern nur die eigenen Methoden des C ++ - Strings verwendet werden, lautet wie folgt:

void processString(string &s) {
    if ( s.empty() ) return;

    //delete leading and trailing spaces of the input string
    int notSpaceStartPos = 0, notSpaceEndPos = s.length() - 1;
    while ( s[notSpaceStartPos] == ' ' ) ++notSpaceStartPos;
    while ( s[notSpaceEndPos] == ' ' ) --notSpaceEndPos;
    if ( notSpaceStartPos > notSpaceEndPos ) { s = ""; return; }
    s = s.substr(notSpaceStartPos, notSpaceEndPos - notSpaceStartPos + 1);

    //reduce multiple spaces between two words to a single space 
    string temp;
    for ( int i = 0; i < s.length(); i++ ) {
        if ( i > 0 && s[i] == ' ' && s[i-1] == ' ' ) continue;
        temp.push_back(s[i]);
    }
    s = temp;
}

Ich habe diese Methode verwendet, um ein LeetCode-Problem zu übergeben. Wörter in einem String umkehren

Charles Wang
quelle
-1
void TrimWhitespaces(std::wstring& str)
{
    if (str.empty())
        return;

    const std::wstring& whitespace = L" \t";
    std::wstring::size_type strBegin = str.find_first_not_of(whitespace);
    std::wstring::size_type strEnd = str.find_last_not_of(whitespace);

    if (strBegin != std::wstring::npos || strEnd != std::wstring::npos)
    {
        strBegin == std::wstring::npos ? 0 : strBegin;
        strEnd == std::wstring::npos ? str.size() : 0;

        const auto strRange = strEnd - strBegin + 1;
        str.substr(strBegin, strRange).swap(str);
    }
    else if (str[0] == ' ' || str[0] == '\t')   // handles non-empty spaces-only or tabs-only
    {
        str = L"";
    }
}

void TrimWhitespacesTest()
{
    std::wstring EmptyStr = L"";
    std::wstring SpacesOnlyStr = L"    ";
    std::wstring TabsOnlyStr = L"           ";
    std::wstring RightSpacesStr = L"12345     ";
    std::wstring LeftSpacesStr = L"     12345";
    std::wstring NoSpacesStr = L"12345";

    TrimWhitespaces(EmptyStr);
    TrimWhitespaces(SpacesOnlyStr);
    TrimWhitespaces(TabsOnlyStr);
    TrimWhitespaces(RightSpacesStr);
    TrimWhitespaces(LeftSpacesStr);
    TrimWhitespaces(NoSpacesStr);

    assert(EmptyStr == L"");
    assert(SpacesOnlyStr == L"");
    assert(TabsOnlyStr == L"");
    assert(RightSpacesStr == L"12345");
    assert(LeftSpacesStr == L"12345");
    assert(NoSpacesStr == L"12345");
}
Ivan Strelets
quelle