コード片などをメモします。 !!!C++関連ウェブサイト ,リンク,内容 ,[C++ - Standards|http://www.open-std.org/JTC1/SC22/WG21/docs/standards],各バージョンのC++言語仕様のドラフト(PDF)を提供。 ,[C++国際標準規格|https://cpprefjp.github.io/international-standard.html],cpprefjp内のページ。上のサイトにあるものより新しいドラフトへのリンクがある。 ,[C++ Core Guidelines|https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines],ガイドライン ,[cpprefjp|http://cpprefjp.github.io/],日本語による標準ライブラリのリファレンスなどを提供。 ,[cppreference.com|http://www.cppreference.com/],標準ライブラリのリファレンス。日本語ページもある。 ,[cplusplus.com|http://www.cplusplus.com/reference/],標準ライブラリのリファレンス。更新が止まっているのかな。C++14以降の情報はなさそう。 !!!コード片 !! 文字列操作 ! 置換 std::stringクラスのメンバ関数[replace|https://cpprefjp.github.io/reference/string/basic_string/replace.html]はオーバーロードの数が多くて圧倒されてしまう。このメンバ関数は、元の文字列の「指定位置の文字列」を別の文字列に置換するのに使える。置換前後の文字列長は変わってもよい。 * string& replace(size_type pos1, size_type n1, const string& str); ** 対象文字列のpos1から長さn1の部分を、strに置換する。 // "hello world" ---> "hell(^^)(^^)(^^)orld" std::string s = "hello world"; s.replace(4, 3, "(^^)(^^)(^^)"); * string& replace(size_type pos, size_type n1, size_type n2, charT c); ** 対象文字列のpos1から長さn1の部分を、n2文字のcに置換する。 // "hello world" ---> "hellZZZZZorld" std::string s = "hello world"; s.replace(4, 3, 5, 'Z'); 文字列中の特定の文字を別の文字に置き換えるのケースでは、にある[std::replace|https://cpprefjp.github.io/reference/algorithm/replace.html]を使える。 // "hello world" ---> "heLLo worLd" std::string s = "hello world"; std::replace(s.begin(), s.end(), 'l', 'L'); ! dirname 相当 find_last_of() と substr() を使ってみる。 std::string dirname(const std::string& path) { return path.substr(0, path.find_last_of('/')); } 短いが、入力文字列によってはdirnameらしくない動きになってしまう。 dirname("/dir/dir/file"); //=> "/dir/dir" dirname("/dir/dir/file/"); //=> "/dir/dir/file" dirname("/dir/dir//file"); //=> "/dir/dir/" dirname("file"); //=> "file" dirname("/file"); //=> "" dirname(""); //=> "" !basename 相当 同じく find_last_of() と substr() を使ってみる。 std::string basename(const std::string& path) { return path.substr(path.find_last_of('/') + 1); } std::string::npos == -1 らしいのでこれでいいみたい。 basename("/dir/dir/file"); //=> "file" basename("/dir/dir/file/"); //=> "" basename("file"); //=> "file" basename(""); //=> "" !行末の空白削除 find_last_not_of() を使えばよさそう。 std::string trim_right( const std::string& line, const std::string& blank = " \t\r\n") { return line.substr(0, line.find_last_not_of(blank) + 1); } trim_right(" str ing\t \r\n"); //=> " str ing" trim_right(" str ing"); //=> " str ing" trim_right("\n"); //=> "" trim_right(""); //=> "" !行頭の空白削除 find_first_not_of() を使う。行末ほど簡単にならなかった。substr() の最初の引数に npos を渡せればいいのに。 std::string trim_left( const std::string& line, const std::string& blank = " \t\r\n") { std::string::size_type begin = line.find_first_not_of(blank); if (begin == line.npos) return ""; return line.substr(begin); } trim_left(" \t str ing "); //=> "str ing " trim_left("str ing "); //=> "str ing " trim_left("\n"); //=> "" trim_left(""); //=> "" !!ストリーム !行単位でストリームから読み込む std::getline()を使うのがよい。エラーとEOFの検出は、std::getline()の戻り値をチェックすることで行う。 std::deque read_lines(std::istream& in) { std::deque result; for (std::string line; std::getline(in, line); /**/) { result.push_back(line); } return result; } !ストリームの内容一度に全部読み込む ストリームから[std::istreambuf_iterator|http://cpprefjp.github.io/reference/iterator/istreambuf_iterator.html]オブジェクトを作って、それを[std::stringのコンストラクタ|http://cpprefjp.github.io/reference/string/basic_string/op_constructor.html]に渡すのがよさそう。 std::string read_stream(std::istream& in) { return std::string( std::istreambuf_iterator{in}, std::istreambuf_iterator{}); } !ファイルサイズの取得 std::basic_istreamクラスのメンバ関数[tellg()|http://cpprefjp.github.io/reference/istream/basic_istream/tellg.html]でストリームの現在位置を得られるのでそれを使う。 std::ifstreamクラスの[コンストラクタ|http://www.cplusplus.com/reference/fstream/basic_ifstream/basic_ifstream/]で指定する[std::ios_base::openmode|http://cpprefjp.github.io/reference/ios/ios_base/type-openmode.html]には「ストリームの最後にシークする」というateという定数があるのでそれも使ってみる。 std::int64_t file_size(const std::string& filename) { std::ifstream ifs( filename, std::ios_base::in | std::ios_base::binary | std::ios_base::ate); return static_cast(ifs.tellg()); } !ファイルコピー std::basic_ostreamクラスにはstd::basic_streambufを引数にとる[operator<<()|http://cpprefjp.github.io/reference/ostream/basic_ostream/op_ostream.html]があるのでそれを使うとよさそう。 あと、std::basic_iosクラスのメンバ関数[exceptions()|http://cpprefjp.github.io/reference/ios/basic_ios/exceptions.html]を呼ぶとエラー時に例外を投げてくれるようになる。 void copy(const std::string& src, const std::string& dst) { using std::ios_base; std::ifstream ifs; ifs.exceptions(ios_base::badbit | ios_base::failbit); ifs.open(src, ios_base::in | ios_base::binary); std::ofstream ofs; ofs.exceptions(ios_base::badbit | ios_base::failbit); ofs.open(dst, ios_base::out | ios_base::binary); ofs << ifs.rdbuf(); } !!連想コンテナ !条件を満たす要素の削除 連想コンテナに対してはstd::remove_if()を用いるイディオムは使えないので、自分でループを書く。後置インクリメントを使う必要がある。 Effective STLの第9項「消去オプションは注意して選択しよう」に説明がある。 void erase_if_value_is( std::map& m, const std::string& condition) { for (std::map::iterator i = m.begin(), end = m.end(); i != end; /* empty */) { if (i->second == condition) { m.erase(i++); } else { ++i; } } } !!!コメント {{comment}}