Stringex

Author: g | 2025-04-24

★★★★☆ (4.4 / 2413 reviews)

avatar 2 reparto

Download gem-stringex packages for ALT Linux. gem-stringex latest versions: 2.8.5. gem-stringex architectures: noarch. gem-stringex linux packages: rpm

Download cytsoft psychrometric chart

stringex/stringex.gemspec at master rsl/stringex - GitHub

ことの経緯大人の事情なのか、std::stringには自身を指定した文字で分割する機能がない。Pythonのstrクラスにはあるのに(splitメソッド)。C++にも欲しい。そんな感じ。対象とする読者std::stringクラスに文字列を分割する機能が欲しい人 ← 多分結構参考になるstd::stringクラスに機能を追加したい人 ← 多分まぁまぁ参考になるC++で既存のクラスを拡張したい人 ← 多分そこそこ参考になるC++以外を所望の人 ← 多分あまり参考にならないオブジェクト指向開発とC++の基本的な知識があれば、さほど難しい内容ではないと思う。(というかこの記事の内容自体C++の基本の範疇と言えると思う)実装長いので分割して解説する。全体のコードを見たい方は以下を参照されたし。string_ex.cppstring_ex.hクラス定義クラス定義はこんな感じ。std::stringクラスを継承したクラスを定義し、実装したいSplitメソッドを定義している。注意すべき点としてはstd::stringクラスを継承しても、コンストラクタと代入演算子(=)は継承されないため、派生クラスの方で実装する必要がある。デフォルトコンストラクタとconst char *にも対応させたいので、3つのコンストラクタを定義した。string_ex.h#pragma once#include #include class StringEx : public std::string { public: StringEx(); StringEx(const char *str); StringEx(const std::string str); std::vectorstd::string> Split(char sep=' '); StringEx& operator=(const char *str); StringEx& operator=(const std::string& str);};コンストラクタコンストラクタの実装は基底クラスの初期化を行うのみである。これはそんな難しいことはないと思う。string_ex.cpp#include #include #include #include "string_ex.h"StringEx::StringEx() : std::string() {}StringEx::StringEx(const char *str) : std::string(str) {}StringEx::StringEx(const std::string str) : std::string(str) {}代入演算子代入演算子も難しいことはなく、基底クラスの代入演算子を呼び出すだけである。代入演算子に限らず、演算子のオーバーロードは種類に応じて引数(IN)と戻り値(OUT)のインターフェースが決まっているので、それに則ることだけ注意すればそれほど難しくないと思う。string_ex.cppStringEx& StringEx::operator=(const char *str) { std::string::operator=(str); return *this;}StringEx& StringEx::operator=(const std::string& str) { std::string::operator=(str); return *this;}メインディッシュPythonのstr.splitメソッドは引数の型が文字列、戻り値の方が文字列のリストである。本ページのSplitメソッドも原則これに則ろうと思うが、引数に複数の文字を含められると処理が面倒なので、引数の型はシンプルに文字(char)とする。戻り値の型はstd::vectorが妥当だろう。Splitメソッドの実現方式はいくつか考えられるが、参考資料が多かったstd::stringstreamを利用する方法を採用した。std::stringstreamの詳細な解説は他に譲るが、それ以外は難しいことはないと思う。string_ex.cppstd::vectorstd::string> StringEx::Split(char sep) { std::vectorstd::string> strs; std::stringstream ss(*this); std::string buf; while(std::getline(ss, buf, sep)) { strs.push_back(buf); } return strs;}単体試験string_ex.hをインクルードしてStringExクラスを利用しようとする人は別途main関数を定義したいと思う。そういう人にとってはstring_ex.cppにmain関数を定義されてると邪魔極まりないと思う。なので、string_ex.cppにおけるmain関数は単体試験専用としてプリプロセッサ定義する。単体試験は引数なしと引数ありの2通りだけ実装した。std::stringクラスを継承しているので、ストリーム演算子(string_ex.cpp#ifdef UNIT_TEST_STRING_EX#include int main(int argc, char **argv) { StringEx str1 = std::string("test0 test1 test2"); std::cout "str1=" + str1 std::endl; std::vectorstd::string> str1s = str1.Split(); std::cout "str1s.size()=" str1s.size() std::endl; for (auto s : str1s) std::cout s std::endl; StringEx str2 = std::string("test0,test1,test2,test3"); std::cout "str2=" + str2 std::endl; std::vectorstd::string> str2s = str2.Split(','); std::cout "str2s.size()=" str2s.size() std::endl; for (auto s : str2s) std::cout s std::endl; return 0;}#endif // UNIT_TEST_STRING_EX実行結果は以下になると思う。実行結果str1=test0 test1 test2str1s.size()=3test0test1test2str2=test0,test1,test2,test3str2s.size()=4test0test1test2test32021/02/17 追記1コメントで有識者から指摘を頂いた。コメント上記の実装ではおそらくほとんどすべての処理系で無害と思いますが、デストラクタが仮想ではない std::string を基底クラスにするのはおすすめできません。それと。std::string の public な操作のみで split が実装できますので、非メンバな関数にするのがおすすめです。なるほど。確かに調べてもstd::stringを基底クラスにしていた資料は少なかった。そもそも、publicな操作のみで完結する=クラス内部で実装する必要はない、ということか、それに加えてデストラクタに関する問題もあるので、非推奨なことをしているわけだ。でだ、コメント上記の実装ではおそらくほとんどすべての処理系で無害と思いますが、デストラクタが仮想ではない std::string を基底クラスにするのはおすすめできません。これの意味がわからなかったので調べた。以下のURLを参考にした。仮想関数C++ でデストラクタを virtual にしなくてはならない条件と理由抜粋デストラクタが virtual でない場合、子クラスのポインタを親クラスのポインタにキャストして使用してはいけません。 なぜならデストラクタが virtual でない場合、親クラスの型のポインタを delete した際には親クラスのデストラクタしか呼ばれないからです。多分、ここが本質と理解している。子クラスのデストラクタが呼ばれないケースがありえる=メモリリークという甚大なリスクを抱えることになる。コメントで「おそらくほとんどすべての処理系で無害」というのは、本ページの実装では子クラスで専用のメモリ確保がないので、デストラクタが呼ばれずともメモリリークの心配はないだろうということか。それでも推奨されないことに変わりはない。2021/02/17 追記2このようなコメントも頂いた。コメント・コンストラクタの引数は const参照がよいです。これについては参考にした以下のページを写景した際のミス(↓こちらのコードはちゃんとconst参照となっている)。stringを継承するただの凡ミスではあるが、なぜconst参照がよいのかがわかっていない。ちゃんと理解していれば、そもそもミスらなかった可能性も十分にある。ということで調べてみる。いや、さすがにconstにするのはわかる。実体渡しではなく、参照渡しにする理由を調べる以下のページを参考にした。C++の基礎 : const 修飾子抜粋参照引数は実際にはポインタであるため、大きな構造体やクラスを引数に渡すときにも効率のよい方法ですが、const をつけない参照渡しであれば、関数により中身を書き換えられる可能性があることになります。参照渡しに const 修飾子をつけることにより、引数の中身を書き換えないことを宣言することができます。大きく以下の2つの理由だろう。参照にする理由→大きな構造体やクラスを渡す際に効率がいい ★今回はこっちの問題に該当constにする理由→関数内部でデータが汚染されるのを防ぐ言われてみれば当たり前のことだった。2021/02/17 追記3次のコメントにいこう。・moveコンストラクタ、move代入へのケアもあったほうが良さそうです。正直moveコンストラクタ、move代入というワードを知らなかった。以下のページを調べて、そういうものがあるというのはわかった。ムーブコンストラクタ|ムーブセマンティクスやコンテナ高速化との関係コンストラクタが継承されないので、当然moveコンストラクタも継承されない。したがってケアが必要ということか。2021/02/17 追記4別の有識者からもコメントを頂いた。コメントどうしても継承したい場合は、非public継承とusingを使用することで、安全性を増すことはできます。フリー関数にしたくない場合はこちらも検討してみても良さそうです。参考 is a Aの関係では無いため、AのポインタにBを代入することはできません。まず、ここがポイントのようだ。追記1で書いたように、StringExが問題になるのは、StringExクラスのポインタをstd::stringにキャストして使用するようなケースだ。非public継承にすれば、そもそもそれができなくなる。しかし、そうなると当然別の問題が生じる。StringExクラスを使う側からstd::stringクラスの機能にアクセスできなくなる。なので、確認していないが、おそらく単体試験で示した以下のようなこと(算術演算子)ができなくなる。それは困る。std::cout "str1=" + str1 std::endl;そもそも継承という行為自体なるべく避けるべき実装のようだ。今回の場合、なるべくstd::stringクラスを内部で抱える実装にするべきらしい。抜粋基本的に継承はコードの複雑性を増すので避けられるなら避けた方が望ましいとされています。できるだけコンポジション(内包)を使って実装する方が良いでしょう。ただ、そのように実装するにしても別の問題が生じる。まさに以下のような内容だ。抜粋例えばstd::vectorの拡張クラスを作りたい時に、std::vectorをメンバとして持つと、std::vectorの持つメソッドを全て再実装しなければいけないという手間が発生します。↓これが有識者の方が伝えたかったことのようだ。usingを使うことで使いたい機能のみのアクセスレベルを引き上げることで、再実装を回避しつつ、親クラスキャストを防ぐことができる。抜粋上記のようなケースでは継承とusingを組み合わせることで実装がシンプルになります。template typename T>class MyVector : private std::vectorT, std::allocatorT>> { // STLコンテナは絶対public継承してはダメですpublic: using std::vectorT>::push_back; // usingでpush_backのアクセスレベルをpublicに引き上げる};2021/02/17 追記のまとめそもそも本ページで実装した機能は非メンバで実装するのが正しい。それでもメンバとして実装するのであれば、少なくともデストラクタがvirtualでないstd::stringクラスをpublic継承するべきではない。↑public継承するとオブジェクトのポインタを親クラスキャストした場合、子クラスのデストラクタが実行されない。修正案としては、privateまたはprotected継承としてusingを用いて必要な機能のみアクセス権をpublicに引き上げる、というのが考えられる。大きなクラスの引数はconst参照してリソース削減すべき継承されないmoveコンストラクタとmove代入演算子のケアが必要。

worm wallpaper

StringEx/StringEx.cs at master LazyMode/StringEx - GitHub

stringex/README.md at master rsl/stringex - GitHub

. Download gem-stringex packages for ALT Linux. gem-stringex latest versions: 2.8.5. gem-stringex architectures: noarch. gem-stringex linux packages: rpm gem(stringex) latest versions: 2.8.5. gem(stringex) architectures: noarch. gem(stringex) linux packages: rpm

GitHub - andruvs/StringEx: StringEx makes it easy to create

Xusory/XusoryEngine/Header/StdEx/StringEx/Private/StringEx

stringex 2.8.6 on Rubygems - Libraries.io

. Download gem-stringex packages for ALT Linux. gem-stringex latest versions: 2.8.5. gem-stringex architectures: noarch. gem-stringex linux packages: rpm

Comments

User5003

ことの経緯大人の事情なのか、std::stringには自身を指定した文字で分割する機能がない。Pythonのstrクラスにはあるのに(splitメソッド)。C++にも欲しい。そんな感じ。対象とする読者std::stringクラスに文字列を分割する機能が欲しい人 ← 多分結構参考になるstd::stringクラスに機能を追加したい人 ← 多分まぁまぁ参考になるC++で既存のクラスを拡張したい人 ← 多分そこそこ参考になるC++以外を所望の人 ← 多分あまり参考にならないオブジェクト指向開発とC++の基本的な知識があれば、さほど難しい内容ではないと思う。(というかこの記事の内容自体C++の基本の範疇と言えると思う)実装長いので分割して解説する。全体のコードを見たい方は以下を参照されたし。string_ex.cppstring_ex.hクラス定義クラス定義はこんな感じ。std::stringクラスを継承したクラスを定義し、実装したいSplitメソッドを定義している。注意すべき点としてはstd::stringクラスを継承しても、コンストラクタと代入演算子(=)は継承されないため、派生クラスの方で実装する必要がある。デフォルトコンストラクタとconst char *にも対応させたいので、3つのコンストラクタを定義した。string_ex.h#pragma once#include #include class StringEx : public std::string { public: StringEx(); StringEx(const char *str); StringEx(const std::string str); std::vectorstd::string> Split(char sep=' '); StringEx& operator=(const char *str); StringEx& operator=(const std::string& str);};コンストラクタコンストラクタの実装は基底クラスの初期化を行うのみである。これはそんな難しいことはないと思う。string_ex.cpp#include #include #include #include "string_ex.h"StringEx::StringEx() : std::string() {}StringEx::StringEx(const char *str) : std::string(str) {}StringEx::StringEx(const std::string str) : std::string(str) {}代入演算子代入演算子も難しいことはなく、基底クラスの代入演算子を呼び出すだけである。代入演算子に限らず、演算子のオーバーロードは種類に応じて引数(IN)と戻り値(OUT)のインターフェースが決まっているので、それに則ることだけ注意すればそれほど難しくないと思う。string_ex.cppStringEx& StringEx::operator=(const char *str) { std::string::operator=(str); return *this;}StringEx& StringEx::operator=(const std::string& str) { std::string::operator=(str); return *this;}メインディッシュPythonのstr.splitメソッドは引数の型が文字列、戻り値の方が文字列のリストである。本ページのSplitメソッドも原則これに則ろうと思うが、引数に複数の文字を含められると処理が面倒なので、引数の型はシンプルに文字(char)とする。戻り値の型はstd::vectorが妥当だろう。Splitメソッドの実現方式はいくつか考えられるが、参考資料が多かったstd::stringstreamを利用する方法を採用した。std::stringstreamの詳細な解説は他に譲るが、それ以外は難しいことはないと思う。string_ex.cppstd::vectorstd::string> StringEx::Split(char sep) { std::vectorstd::string> strs; std::stringstream ss(*this); std::string buf; while(std::getline(ss, buf, sep)) { strs.push_back(buf); } return strs;}単体試験string_ex.hをインクルードしてStringExクラスを利用しようとする人は別途main関数を定義したいと思う。そういう人にとってはstring_ex.cppにmain関数を定義されてると邪魔極まりないと思う。なので、string_ex.cppにおけるmain関数は単体試験専用としてプリプロセッサ定義する。単体試験は引数なしと引数ありの2通りだけ実装した。std::stringクラスを継承しているので、ストリーム演算子(string_ex.cpp#ifdef UNIT_TEST_STRING_EX#include int main(int argc, char **argv) { StringEx str1 = std::string("test0 test1 test2"); std::cout "str1=" + str1 std::endl; std::vectorstd::string> str1s = str1.Split(); std::cout "str1s.size()=" str1s.size() std::endl; for (auto s : str1s) std::cout s std::endl; StringEx str2 = std::string("test0,test1,test2,test3"); std::cout "str2=" + str2 std::endl; std::vectorstd::string> str2s = str2.Split(','); std::cout "str2s.size()=" str2s.size() std::endl; for (auto s : str2s) std::cout s std::endl; return 0;}#endif // UNIT_TEST_STRING_EX実行結果は以下になると思う。実行結果str1=test0 test1 test2str1s.size()=3test0test1test2str2=test0,test1,test2,test3str2s.size()=4test0test1test2test32021/02/17 追記1コメントで有識者から指摘を頂いた。コメント上記の実装ではおそらくほとんどすべての処理系で無害と思いますが、デストラクタが仮想ではない std::string を基底クラスにするのはおすすめできません。それと。std::string の public な操作のみで split が実装できますので、非メンバな関数にするのがおすすめです。なるほど。確かに調べてもstd::stringを基底クラスにしていた資料は少なかった。そもそも、publicな操作のみで完結する=クラス内部で実装する必要はない、ということか、それに加えてデストラクタに関する問題もあるので、非推奨なことをしているわけだ。でだ、コメント上記の実装ではおそらくほとんどすべての処理系で無害と思いますが、デストラクタが仮想ではない std::string を基底クラスにするのはおすすめできません。これの意味がわからなかったので調べた。以下のURLを参考にした。仮想関数C++ でデストラクタを virtual にしなくてはならない条件と理由抜粋デストラクタが virtual でない場合、子クラスのポインタを親クラスのポインタにキャストして使用してはいけません。 なぜならデストラクタが virtual でない場合、親クラスの型のポインタを delete した際には親クラスのデストラクタしか呼ばれないからです。多分、ここが本質と理解している。子クラスのデストラクタが呼ばれないケースがありえる=メモリリークという甚大なリスクを抱えることになる。コメントで「おそらくほとんどすべての処理系で無害」というのは、本ページの実装では子クラスで専用のメモリ確保がないので、デストラクタが呼ばれずともメモリリークの心配はないだろうということか。それでも推奨されないことに変わりはない。2021/02/17 追記2このようなコメントも頂いた。コメント・コンストラクタの引数は const参照がよいです。これについては参考にした以下のページを写景した際のミス(↓こちらのコードはちゃんとconst参照となっている)。stringを継承するただの凡ミスではあるが、なぜconst参照がよいのかがわかっていない。ちゃんと理解していれば、そもそもミスらなかった可能性も十分にある。ということで調べてみる。いや、さすがにconstにするのはわかる。実体渡しではなく、参照渡しにする理由を調べる以下のページを参考にした。C++の基礎 : const 修飾子抜粋参照引数は実際にはポインタであるため、大きな構造体やクラスを引数に渡すときにも効率のよい方法ですが、const をつけない参照渡しであれば、関数により中身を書き換えられる可能性があることになります。参照渡しに const 修飾子をつけることにより、引数の中身を書き換えないことを宣言することができます。大きく以下の2つの理由だろう。参照にする理由→大きな構造体やクラスを渡す際に効率がいい ★今回はこっちの問題に該当constにする理由→関数内部でデータが汚染されるのを防ぐ言われてみれば当たり前のことだった。2021/02/17 追記3次のコメントにいこう。・moveコンストラクタ、move代入へのケアもあったほうが良さそうです。正直moveコンストラクタ、move代入というワードを知らなかった。以下のページを調べて、そういうものがあるというのはわかった。ムーブコンストラクタ|ムーブセマンティクスやコンテナ高速化との関係コンストラクタが継承されないので、当然moveコンストラクタも継承されない。したがってケアが必要ということか。2021/02/17 追記4別の有識者からもコメントを頂いた。コメントどうしても継承したい場合は、非public継承とusingを使用することで、安全性を増すことはできます。フリー関数にしたくない場合はこちらも検討してみても良さそうです。参考 is a Aの関係では無いため、AのポインタにBを代入することはできません。まず、ここがポイントのようだ。追記1で書いたように、StringExが問題になるのは、StringExクラスのポインタをstd::stringにキャストして使用するようなケースだ。非public継承にすれば、そもそもそれができなくなる。しかし、そうなると当然別の問題が生じる。StringExクラスを使う側からstd::stringクラスの機能にアクセスできなくなる。なので、確認していないが、おそらく単体試験で示した以下のようなこと(算術演算子)ができなくなる。それは困る。std::cout "str1=" + str1 std::endl;そもそも継承という行為自体なるべく避けるべき実装のようだ。今回の場合、なるべくstd::stringクラスを内部で抱える実装にするべきらしい。抜粋基本的に継承はコードの複雑性を増すので避けられるなら避けた方が望ましいとされています。できるだけコンポジション(内包)を使って実装する方が良いでしょう。ただ、そのように実装するにしても別の問題が生じる。まさに以下のような内容だ。抜粋例えばstd::vectorの拡張クラスを作りたい時に、std::vectorをメンバとして持つと、std::vectorの持つメソッドを全て再実装しなければいけないという手間が発生します。↓これが有識者の方が伝えたかったことのようだ。usingを使うことで使いたい機能のみのアクセスレベルを引き上げることで、再実装を回避しつつ、親クラスキャストを防ぐことができる。抜粋上記のようなケースでは継承とusingを組み合わせることで実装がシンプルになります。template typename T>class MyVector : private std::vectorT, std::allocatorT>> { // STLコンテナは絶対public継承してはダメですpublic: using std::vectorT>::push_back; // usingでpush_backのアクセスレベルをpublicに引き上げる};2021/02/17 追記のまとめそもそも本ページで実装した機能は非メンバで実装するのが正しい。それでもメンバとして実装するのであれば、少なくともデストラクタがvirtualでないstd::stringクラスをpublic継承するべきではない。↑public継承するとオブジェクトのポインタを親クラスキャストした場合、子クラスのデストラクタが実行されない。修正案としては、privateまたはprotected継承としてusingを用いて必要な機能のみアクセス権をpublicに引き上げる、というのが考えられる。大きなクラスの引数はconst参照してリソース削減すべき継承されないmoveコンストラクタとmove代入演算子のケアが必要。

2025-04-03

Add Comment