Ответ 1
if(str.find_first_not_of(' ') != std::string::npos)
{
// There a non-space.
}
Я просто разговаривал с другом о том, что было бы самым эффективным способом проверить, есть ли у 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;
}
Я ищу отзыв для этого кода, и более эффективные способы выполнения этой задачи также приветствуются.
if(str.find_first_not_of(' ') != std::string::npos)
{
// There a non-space.
}
В С++ 11 можно использовать алгоритм all_of
:
// Check if s consists only of whitespaces
bool whiteSpacesOnly = std::all_of(s.begin(),s.end(),isspace);
Почему так много работы, так много набрав?
bool has_only_spaces(const std::string& str) {
return str.find_first_not_of (' ') == str.npos;
}
Было бы проще сделать это:
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;
}
Это имеет преимущество, заключающееся в том, что вы возвращаетесь рано, как только обнаруживается непространственный символ, поэтому он будет немного более эффективным, чем решения, которые исследуют всю строку.
Использование strtok - это плохой стиль! strtok модифицирует буфер, который он токенизирует (он заменяет символы разделителя на \0).
Здесь не изменяющая версия.
const char* p = str.c_str();
while(*p == ' ') ++p;
return *p != 0;
Его можно оптимизировать еще дальше, если вы перебираете его в машинных словах. Чтобы быть переносимым, вам также необходимо будет учитывать соответствие.
Здесь используется только 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
маловероятно, что вы будете бить оптимизированный наивный алгоритм компилятора для этого, например
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;
Я не одобряю вас 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, которое может быть быстрее.
Что-то вроде:
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>
).
Hm... Я бы сделал это:
for (auto i = str.begin(); i != str.end() ++i)
if (!isspace(i))
return false;
Псевдокод, isspace находится в cctype для С++.
Edit: Спасибо Джеймсу за то, что указали, что isspace имеет поведение undefined на подписанных символах.
Если вы используете CString
, вы можете сделать
CString myString = " "; // All whitespace
if(myString.Trim().IsEmpty())
{
// string is all whitespace
}
Это дает возможность обрезать все символы новой строки, пробела и табуляции.