<stx/string>
DDJ-J 1998年5月号で紹介したSTL拡張コンポーネント”STX”の改版です。C Magazine Jan 2000で公開したtokenizerをreviseしました。
tokenizer<class String>
標準C++ライブラリが提供する文字列クラス basic_string<charT>
をトークン分割するクラスです。テンプレート引数にはstd::string
もしくは std::wstring
を与えることができます。
※ マルチバイト文字(Shift-JIS, EUCなど)は正しく分割できません。一旦DBCS(UNICODE)に変換しstd::wstring
で扱うか、もしくは stx::c_tokenizer<unsigned char>
をお使いください。
template<class String> class tokenizer { private: String::size_type cur_; String str_; String del_; bool ret_; void skip(); public: typedef std::pair<String::size_type,String::size_type> range_type; tokenizer(const String& str, const String& del, bool ret=false); bool empty(); String next(); range_type next_range(); void set_str(const String& str); void set_delimiter(const String& del, bool ret=false); size_t count() const; };
// sample // "apple,banana,cherry" を "," で区切る stx::tokenizer<string> tok("apple,banana,cherry", ","); while ( !tok.empty() ) { cout << tok.next() << " "; } cout << endl;
tokenizer (コンストラクタ)
template<class String> tokenizer<String>::tokenizer(const String& str, const String& del, bool ret) : cur_(0), str_(str), del_(del), ret_(ret) {}
- str
- :トークン分割対象となる文字列
- del
- :トークンを区切る文字の集合
- ret
- :区切り文字をトークンとして扱うならtrue
ret == true のとき、区切り文字をトークンとして扱います。たとえば、
// sample // "apple_banana__cherry_" を "_" で区切る bool ret = false; stx::tokenizer<string> tok("apple_banana__cherry_", "_", ret); while ( !tok.empty() ) { cout << tok.next() << " "; } cout << endl;
では “apple”, “banana”, “cherry” が切り出されますが、ret = true とすると、”apple”, “_”, “banana”, “_”, “_”, “cherry”, “_” が切り出されます。
skip (private)
template<class String> void tokenizer<String>::skip() { if ( cur_ == str_.length() ) cur_ = String::npos; if ( !ret_ && cur_ != String::npos ) { String::size_type tmp = str_.find_first_not_of(del_, cur_); if ( tmp != String::npos ) cur_ = tmp; } }
empty
template<class String> bool tokenizer<String>::empty() { skip(); return cur_ == String::npos; }
切り出すトークンが見つからないとき true を返します。
next
template<class String> String tokenizer<String>::next() { range_type range = next_range(); return str_.substr(range.first, range.second); }
切り出されたトークンを返します。
next_range
template<class String> tokenizer<String>::range_type tokenizer<String>::next_range() { skip(); String::size_type start = cur_; String::size_type tmp = cur_; if ( cur_ != String::npos ) cur_ = str_.find_first_of(del_,cur_); if ( cur_ == String::npos ) return range_type(start,str_.length()-start); if ( ret_ && start == cur_ && del_.find(str_[cur_]) != String::npos ) ++cur_; return range_type(start,cur_-start); }
トークンを切り出し、その位置と長さを表す std::pair<String::size_type,String::size_type> range
を返します。range.first
はトークンの開始位置、range.second
はトークンの長さです。
set_str
template<class String> void tokenizer<String>::set_str(const String& str) { str_ = str; cur_ = 0; }
トークン分割対象となる文字列を設定します。トークン分割の開始位置を0に設定します。
set_delimiter
template<class String> void tokenizer<String>::set_delimiter(const String& delim, bool ret) { del_ = delim; ret_ = ret; }
区切り文字の集合を設定します。区切り文字をトークンとして扱うときは第2引数を true としてください。
count
template<class String> size_t tokenizer<String>::count() const { size_t count = 0; String::size_type currpos = cur_; while ( currpos != String::npos ) { if ( !ret_ ) { currpos = str_.find_first_not_of(del_,currpos); if ( currpos == String::npos ) { ++count; break; } } else if ( currpos == str_.length() ) { break; } String::size_type start = currpos; if ( currpos != String::npos ) currpos = str_.find_first_of(del_,currpos); if ( currpos == String::npos ) { ++count; break; } if ( ret_ && start == currpos && del_.find(str_[currpos]) != String::npos ) ++currpos; ++count; } return count; }
現在の位置から切り出されるトークンの数を返します。
string_tokenizer / wstring_tokenizer
typedef tokenizer<std::string> string_tokenizer; typedef tokenizer<std::wstring> wstring_tokenizer;
使用頻度の多いtokenizer<std::string>
および tokenizer<std::wstring>
をそれぞれ string_tokenizer,wstring_tokenizerとtypedefしました。