webentwicklung-frage-antwort-db.com.de

Effiziente Möglichkeit zu überprüfen, ob std :: string nur Leerzeichen enthält

Ich habe gerade mit einem Freund darüber gesprochen, was der effizienteste Weg ist, um zu überprüfen, ob ein std :: string nur Leerzeichen enthält. Er muss dies für ein Embedded-Projekt tun, an dem er arbeitet, und diese Optimierung scheint ihm wichtig zu sein.

Ich habe den folgenden Code entwickelt, er verwendet strtok().

bool has_only_spaces(std::string& str)
{
    char* token = strtok(const_cast<char*>(str.c_str()), " ");

    while (token != NULL)
    {   
        if (*token != ' ')
        {   
            return true;
        }   
    }   
    return false;
}

Ich bin auf der Suche nach Feedback zu diesem Code und effizientere Wege, um diese Aufgabe auszuführen, sind ebenfalls willkommen.

32
karlphillip
if(str.find_first_not_of(' ') != std::string::npos)
{
    // There's a non-space.
}
79
Mark B

In C++ 11 kann der all_of-Algorithmus verwendet werden:

// Check if s consists only of whitespaces
bool whiteSpacesOnly = std::all_of(s.begin(),s.end(),isspace);
42

Warum so viel Arbeit, so viel Tippen?

bool has_only_spaces(const std::string& str) {
   return str.find_first_not_of (' ') == str.npos;
}
15
David Hammen

Wäre es nicht einfacher zu machen:

bool has_only_spaces(const std::string &str)
{
    for (std::string::const_iterator it = str.begin(); it != str.end(); ++it)
    {
        if (*it != ' ') return false;
    }
    return true;
}

Dies hat den Vorteil, dass es so bald wie möglich zurückkehrt, sobald ein Zeichen ohne Leerzeichen gefunden wird. Es ist also etwas effizienter als Lösungen, die den gesamten String untersuchen.

6
Tom

Strtok zu verwenden ist ein schlechter Stil! strtok ändert den Puffer, den er tokeniert (er ersetzt die Trennzeichenzeichen durch\0).

Hier ist eine nicht modifizierende Version.

const char* p = str.c_str();
while(*p == ' ') ++p;
return *p != 0;

Es kann sogar noch weiter optimiert werden, wenn Sie es in Word-Chunks der Maschine durchlaufen. Um tragbar zu sein, müssen Sie auch die Ausrichtung berücksichtigen. 

2

So prüfen Sie, ob der String in C++ 11 nur Leerzeichen enthält:

bool is_whitespace(const std::string& s) {
  return std::all_of(s.begin(), s.end(), isspace);
}

in pre-c ++ 11:

bool is_whitespace(const std::string& s) {
  for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) {
    const char this_char = *it;
    if (!isspace(this_char)) {
      return false;
    }
  }
  return true;
}
2
ericcurtin

Hier ist eine, die nur STL verwendet (erfordert C++ 11)

inline bool isBlank(const std::string& s)
{
    return std::all_of(s.cbegin(),s.cend(),[](char c) { return std::isspace(c); });
}

Es ist darauf angewiesen, dass bei einem leeren String (begin = end) auch std :: all_of true zurückgibt

Hier ist ein kleines Testprogramm: http://cpp.sh/2tx6

2
GameSalutes

es ist höchst unwahrscheinlich, dass Sie dafür einen Compiler-optimierten naiven Algorithmus schlagen, z.

string::iterator it(str.begin()), end(str.end())    
for(; it != end && *it == ' '; ++it);
return it == end;

BEARBEITEN: Eigentlich - es geht schneller (abhängig von der Größe des Strings und dem verfügbaren Speicher). 

std::string ns(str.size(), ' '); 
return ns == str;

BEARBEITEN: Eigentlich oben ist nicht schnell. Es ist dumm ... bleib bei der naiven Implementierung, der Optimierer wird alles über das ...

BEARBEITEN SIE WIEDER: verdammt, ich denke, es ist besser, sich die Funktionen in std::string anzusehen.

return str.find_first_not_of(' ') == string::npos;
1
Nim

Ich stimme nicht zu, dass Sie const_casting oben verwenden und strtok verwenden.

Ein std :: string kann eingebettete Nullen enthalten. Nehmen wir jedoch an, dass es alle 32 Zeichen ASCII sein wird, bevor Sie das NULL-Abschlusszeichen drücken.

Eine Möglichkeit, wie Sie dies erreichen können, ist eine einfache Schleife, und ich gehe von const char * aus.

bool all_spaces( const char * v )
{
   for ( ; *v; ++v )
   {
      if( *v != ' ' )
          return false;
   }
   return true;
}

Bei größeren Zeichenfolgen können Sie Word-at-a-time bis zum letzten Word überprüfen und dann annehmen, dass das 32-Bit-Word (sagen wir) 0x20202020 ist.

1
CashCow

So etwas wie:

return std::find_if(
            str.begin(), str.end(),
            std::bind2nd( std::not_equal_to<char>(), ' ' ) )
    == str.end();

Wenn Sie sich für Leerzeichen interessieren und nicht nur für das Leerzeichen , Ist es am besten, ein Prädikat zu definieren und es zu verwenden:

struct IsNotSpace
{
    bool operator()( char ch ) const
    {
        return ! ::is_space( static_cast<unsigned char>( ch ) );
    }
};

Wenn Sie überhaupt eine Textverarbeitung durchführen, ist eine Sammlung solcher einfachen Prädikate .__ von unschätzbarem Wert (und sie lassen sich leicht aus der Liste der Funktionen in <ctype.h> generieren ).

1
James Kanze

Wenn Sie CString verwenden, können Sie dies tun

CString myString = "    "; // All whitespace
if(myString.Trim().IsEmpty())
{
    // string is all whitespace
}

Dies hat den Vorteil, dass alle Zeilenumbrüche, Leerzeichen und Tabulatorzeichen abgeschnitten werden.

0
Steztric

Hm ... ich würde das machen:

for (auto i = str.begin(); i != str.end() ++i)
    if (!isspace(i))
       return false;

Pseudo-Code, isspace befindet sich in Cctype für C++.

Edit: Danke an James für den Hinweis, dass isspace unbestimmtes Verhalten bei signierten Zeichen hat.

0
LainIwakura