必要に迫られて書き直すなど。
せっかくなのでイテレータで受け付けるようにしてみた。
加えて。前回のはシングルラインしかきちんと処理できなかったのを、マルチラインも処理できるようにした。条件をふたつ加えただけですけど。
#ifndef EMATTSAN_TABTOSPACE_H #define EMATTSAN_TABTOSPACE_H namespace emattsan { template<typename InputIterator, typename OutputIterator> OutputIterator tabToSpace(int tabSize, InputIterator begin, InputIterator end, OutputIterator out) { int spaceSize = tabSize; for(InputIterator i = begin; i != end; ++i) { if(*i == '\t') { while(spaceSize-- != 0) { *out = ' '; ++out; } spaceSize = tabSize; } else { *out = *i; ++out; --spaceSize; if((spaceSize == 0) || (*i == '\n') || (*i == '\r')) { spaceSize = tabSize; } } } return out; } } // namespace emattsan #endif//EMATTSAN_TABTOSPACE_H
実践その1:std::string
からstd::string
へ。
#include "TabToSpace.h" #include <iostream> #include <string> int main(int, char* []) { std::string source("\ta\tbc\tdef\na\tbc\td\n"); // 全部TABだったときの最大長を確保すれば大丈夫だろう、という大雑把な確保の仕方 std::string result(source.size() * 4, '\0'); // 戻り値に最後の文字の次の位置が返る std::string::iterator eos = emattsan::tabToSpace(4, source.begin(), source.end(), result.begin()); // 余った領域の文字列を削除 result.erase(eos, result.end()); std::cout << result << std::endl; return 0; }
実行結果は省略。
実践その2:std::string
からstd::string
へ、再。
文字列が伸びるコストを無視していいなら、最初に領域を確保しないで伸びるに任せてもOK。そのばあいstd::back_insert_iterator
を利用。std::back_inserter
関数テンプレートを使えば自動生成してくれます。
#include "TabToSpace.h" #include <iostream> #include <string> #include <iterator> int main(int, char* []) { std::string source("\ta\tbc\tdef\na\tbc\td\n"); std::string result; emattsan::tabToSpace(4, source.begin(), source.end(), std::back_inserter(result)); std::cout << result << std::endl; return 0; }
実践その3:C文字列からC文字列へ。
ポインタもイテレータ。ゆえにポインタをわたしてもOK。
#include "TabToSpace.h" #include <iostream> #include <cstring> int main(int, char* []) { char source[] = "\ta\tbc\tdef\na\tbc\td\n"; // 全部TABだったときの最大長を確保すれば大丈夫だろう、という大雑把な確保の仕方 char result[sizeof(source) * 4]; // 戻り値に最後の文字の次の位置が返る char* eos = emattsan::tabToSpace(4, source, source + std::strlen(source), result); // ゼロ終端を書き込む *eos = '\0'; std::cout << result << std::endl; return 0; }
実践その4:ストリームからストリームへ。
std::istream_iterator
、std::istream_iterator
を使えばストリームもイテレータで扱えるのでストリームもOK。この例では標準入力から標準出力へ。
#include "TabToSpace.h" #include <iostream> #include <iterator> int main(int, char* []) { // 空白を読みとばす (skip white space) フラグをオフにする std::cin.unsetf(std::ios::skipws); std::istream_iterator<char> begin(std::cin); // 読み始めの位置をあらわすイテレータ std::istream_iterator<char> end; // 読み終わりの位置をあらわすイテレータ std::ostream_iterator<char> out(std::cout); // 書き始めの位置をあらわすイテレータ emattsan::tabToSpace(4, begin, end, out); return 0; }