c++にpythonのような強力な文字列操作を!

自分はpythonをよく利用するのですが、pythonは文字列操作が割と強力な印象を受けます(特にスライス)
普段使いのC++でもpythonみたいに文字列操作したい!
ってことでstd::stringを継承したpythonのstr型のメソッドがほとんどそのまま使える文字列クラスを作ってみました。

py_string

https://github.com/ChanTsune/py_string

使用感的にはstd::stringでpythonのstr型のメソッドが使えるだけですかね(笑)。 std::stringを継承しているのでstd::stringで出来ることは全部できます。
シングルヘッダーライブラリにしたのでインクルードするだけですぐに使えます。
名前空間はpyです。

使い方

基本形

#include "py_string.hpp"
#include <iostream>

using namespace std;

int main(int argc,char*argv[])
{
  py::string pystr = "hello world!";//py_stringでもpy::stringと同じ

  cout << pystr << endl;
}

std::stringと同じです。

split

py::string spstr = "12,3,4-2,2,3";
std::deque<py::string> slist; //std::vectorでもOK

spstr.split(slist, ",",2);
for (auto &&s : slist)
{
    cout << s << endl;
}
//出力
//12
//3
//4-2,2

第一引数はテンプレートを使っているのでpush_backをメンバ関数に持っているcontainerクラスなら何でもいけるはずです。
第二引数を省略するとタブやスペースなどの空白文字で分割されます。
第三引数で分割する最大数を指定できます。分割後の要素数は指定した数+1になります。
std::stringにほしい機能の一つです。そのうち対応してくれないかなぁ…

format

py::string fstr = "{} is {} than {}";
cout << fstr.format(3,"bigger",1) << endl;
//"3 is bigger than 1."
cout << fstr.format(2,"smaller",4) << endl;
//"2 is smaller than 4."

{}が先頭から順に引数リストで置き換えられます。

py::string fstr = "{0} is {0}";
cout << fstr.format(3) << endl;
//"3 is 3."
cout << fstr.format(2) << endl;
//"2 is 2."

{N}とすることでN番目の引数に置き換えることが可能です。
そのほかにもpythonのstr型のformatメソッド式のフォーマットも一通り対応しています。

replace

py::string rstr = "1+2-3";
cout << rstr.pyreplace("-","=");
//1+2=3

文字列中に登場する第一引数とマッチするすべての要素が第二引数で置き換えられます。
第三引数に数を渡すと置き換える最大数を指定できます。
※std::stringのreplaceと違って自身が置き換わるのではなく置換後の文字列が返ります。

slice

添字演算子[]がc++の制約で一つしか引数が取れなかったので初期化リストっぽい書き方で対応することにしました。


pystr[{0,5}];
//hello

若干書きづらいですが許容範囲内かな?


string[0:3]
string[3:]
string[::-1]

上記のコードに相当する書き方は

string[{0,3}];
string[{3,nullptr}];
string[{nullptr,nullptr,-1}];

です。
コロンだけはnullptrで代用することにしました。
この書き方が気持ち悪いと感じる人は、

string.slice(0,3);
string.slice(3,nullptr);
string.slice(nullptr,nullptr,-1);

といったようにメンバ関数の形でも同じように呼び出せます。

添字演算子[]

py::string astr = "0123456789";
cout << astr[0] << endl;
// 0
cout << astr[-1] << endl; //一番最後の要素
// 9
cout << astr[-3] << endl; //後ろから三番目の要素
// 7

添字演算子をオーバーライドして負の数を利用して後ろからのアクセスもできるようにしました。代入も可能です。
atでも同じことができるようにしてあります。

その他

一部のstd::stringと名前が被るかつオーバーロード解決ができないメソッドにはpy~って感じの名前をつけています。

それぞれのメソッドの動作は
https://docs.python.org/ja/3/library/stdtypes.html#string-methods

を参照してください。

言語機能的に実装が難しい、あるいは私の技能不足で実装しきれていないメソッドも少しあります。
※pythonではエラーを送出するメソッド(e.g. indexなど)はエラーを送出しないようにしています。

今後もできるものは実装していきたいので、
もし「これできるよ!」とか「こっちのほうが効率的じゃない?」みたいなのがあれば是非プルリクください。
エラー報告もしてもらえると助かります。

お問い合わせフォームまでお願いします。
このメモは過去にQiitaに投稿した記事を自分のサイトにお引越しし加筆訂正したものです