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's a non-space.
}
C++ 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;
}
これには、スペース以外の文字が見つかるとすぐに戻るという利点があるため、文字列全体を調べるソリューションよりもわずかに効率的です。
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;
}
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
Strtokをそのように使用するのは悪いスタイルです! strtok 変更トークン化するバッファー(区切り文字を\ 0に置き換えます)。
これが非修正バージョンです。
const char* p = str.c_str();
while(*p == ' ') ++p;
return *p != 0;
マシンのWordチャンクで繰り返し処理する場合、さらに最適化できます。ポータブルにするためには、アライメントも考慮する必要があります。
このためにコンパイラーに最適化された素朴なアルゴリズムに勝る可能性は非常に低いです。
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;
上記のconst_castingとstrtokの使用を承認しません。
Std :: stringにはnullを埋め込むことができますが、NULLターミネータに到達する前にすべてASCII 32文字になると仮定します。
これにアプローチする1つの方法は、単純なループを使用することです。constchar *を想定します。
bool all_spaces( const char * v )
{
for ( ; *v; ++v )
{
if( *v != ' ' )
return false;
}
return true;
}
大きな文字列の場合、最後のWordに到達するまで一度にWordをチェックし、32ビットWord(たとえば)が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>
の関数のリストから自動的に生成するのは簡単です)。
CString
を使用している場合は、次のことができます。
CString myString = " "; // All whitespace
if(myString.Trim().IsEmpty())
{
// string is all whitespace
}
これには、すべての改行文字、スペース文字、タブ文字を切り取るという利点があります。
うーん...私はこれをやる:
for (auto i = str.begin(); i != str.end() ++i)
if (!isspace(i))
return false;
擬似コード、isspaceはC++のcctypeにあります。
編集:isspaceが署名付き文字に対して未定義の動作をしていることを指摘してくれたJamesに感謝します。