Подтвердить что ты не робот

Эффективный способ проверки наличия std::string только пробелов

Я просто разговаривал с другом о том, что было бы самым эффективным способом проверить, есть ли у 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;
}

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

4b9b3361

Ответ 1

if(str.find_first_not_of(' ') != std::string::npos)
{
    // There a non-space.
}

Ответ 2

В С++ 11 можно использовать алгоритм all_of:

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

Ответ 3

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

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

Ответ 4

Было бы проще сделать это:

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

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

Ответ 5

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

Здесь не изменяющая версия.

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

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

Ответ 6

Здесь используется только STL (требуется С++ 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

Ответ 7

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

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

EDIT: На самом деле - есть более быстрый способ (в зависимости от размера строки и доступной памяти).

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

EDIT: на самом деле выше не быстро.. он daft... придерживаться наивной реализации, оптимизатор будет во всем этом...

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

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

Ответ 8

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

A std::string может содержать встроенные нули, но пусть предполагается, что все символы ASCII 32 будут удалены с помощью NULL-терминатора.

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

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

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

Ответ 9

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

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

Ответ 10

Hm... Я бы сделал это:

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

Псевдокод, isspace находится в cctype для С++.

Edit: Спасибо Джеймсу за то, что указали, что isspace имеет поведение undefined на подписанных символах.

Ответ 11

Если вы используете CString, вы можете сделать

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

Это дает возможность обрезать все символы новой строки, пробела и табуляции.