Эффективный способ проверить, есть ли в std :: string только пробелы - PullRequest
32 голосов
/ 22 июня 2011

Я только что говорил с другом о том, что было бы наиболее эффективным способом проверить, есть ли в std :: string только пробелы.Он должен сделать это во встроенном проекте, над которым он работает, и, очевидно, для него важен этот вид оптимизации.

Я придумал следующий код, он использует 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;
}

Мне нужны отзывы об этом коде, и приветствуются более эффективные способы выполнения этой задачи.

Ответы [ 12 ]

81 голосов
/ 22 июня 2011
if(str.find_first_not_of(' ') != std::string::npos)
{
    // There's a non-space.
}
41 голосов
/ 14 августа 2013

В C ++ 11 может использоваться алгоритм all_of:

// Check if s consists only of whitespaces
bool whiteSpacesOnly = std::all_of(s.begin(),s.end(),isspace);
15 голосов
/ 22 июня 2011

Почему так много работы, так много печатания?

bool has_only_spaces(const std::string& str) {
   return str.find_first_not_of (' ') == str.npos;
}
6 голосов
/ 22 июня 2011

Разве это не было бы проще сделать:

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

Это имеет преимущество, заключающееся в том, что он возвращается рано, как только обнаруживается непробельный символ, поэтому он будет незначительно более эффективным, чем решения, которые исследуютвся строка.

3 голосов
/ 05 апреля 2018

Чтобы проверить, имеет ли строка только пробел в c ++ 11:

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

в pre-c ++ 11:

bool is_whitespace(const std::string& s) {
  for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) {
    if (!isspace(*it)) {
      return false;
    }
  }
  return true;
}
3 голосов
/ 10 апреля 2016

Вот тот, который использует только STL (требуется C ++ 11)

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

Он основан на том факте, что если строка пуста (begin = end), std :: all_of также возвращает true

Вот небольшая тестовая программа: http://cpp.sh/2tx6

2 голосов
/ 22 июня 2011

Использование strtok - это плохой стиль! strtok изменяет буфер, который он маркирует (он заменяет символы разделителя на \ 0).

Вот не модифицирующая версия.

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

Он может быть оптимизирован еще больше, если вы выполните итерации по нему в кусках машинного слова. Чтобы быть портативным, вы также должны принять во внимание выравнивание.

1 голос
/ 22 июня 2011

Что-то вроде:

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

Если вас интересует не только пробел, но и пробел, тогда лучше всего определить предикат и использовать его:

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

Если вы вообще занимаетесь обработкой текста, коллекция таких простых предикаты будут неоценимы (и их легко генерировать автоматически из списка функций в <ctype.h>).

1 голос
/ 22 июня 2011

Я не одобряю использование вами const_casting выше и использование strtok.

Std :: string может содержать встроенные нули, но давайте предположим, что все символы ASCII 32 будут до того, как вы нажмете на терминатор NULL.

Один из способов решения этой проблемы - простой цикл, и я предполагаю, что const char *.

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

Для больших строк вы можете проверять пословное слово, пока не достигнетеПоследнее слово, а затем предположим, что 32-разрядное слово (скажем) будет 0x20202020, что может быть быстрее.

1 голос
/ 22 июня 2011

маловероятно, что для этого вам понадобится оптимизированный компилятором наивный алгоритм, например

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

РЕДАКТИРОВАТЬ: На самом деле - есть более быстрый способ (в зависимости от размера строки и доступной памяти) ..

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

РЕДАКТИРОВАТЬ: на самом деле выше не быстро ... это глупо ... придерживайтесь наивной реализации, оптимизатор будет во всем этом ...

ИЗМЕНИТЬ СНОВА: черт возьми, ядумаю, лучше взглянуть на функции в std::string

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