それで、私はスクリプト言語を構築しています。私の目標の 1 つは、便利な文字列操作です。C++でいくつかのアイデアを試しました。
- バイト シーケンスとしての文字列と、コード ポイント インデックスを含むベクトルを返すフリー関数。
- 文字列とインデックスを含むベクトルを結合するラッパー クラス。
どちらのアイデアにも問題があり、その問題は、何を返すべきかということでした。文字にすることはできません。文字列の場合は、スペースが無駄になります。
最終的に、正確に 4 バイトの char 配列のラッパー クラスを作成しました。これは、メモリ内に正確に 4 バイトの文字列で、多かれ少なかれありません。
このクラスを作成した後、別のクラスのクラスにラップして、std::vector
そこからビルドして、文字列型のコードポイントを作成したいという誘惑にかられました。これが良いアプローチかどうかはわかりませんが、最終的にははるかに便利になりますが、より多くのスペースを浪費することになります。
したがって、コードを投稿する前に、より整理されたアイデアのリストを次に示します。
- 私の文字タイプは、バイトでも書記素でもなく、コードポイントです。私はそれを Go 言語のルーンのような名前にしました。
- 一連の分解されたルーンとしての文字列。したがって、インデックス付けとスライス O1 が作成されます。
- ルーンはプリミティブではなくクラスになったため、Unicode の空白を検出するメソッドで拡張できます。
mysring[0].is_whitespace()
- 書記素の扱い方がまだわかりません。
興味深い事実!ルーン クラスのプロトタイプを作成する方法で奇妙な点は、常に UTF8 で出力されることです。私のルーンは int32 ではなく 4 バイトの文字列であるため、これにはいくつかの興味深いプロパティがあります。
私のコード:
class rune {
char data[4] {};
public:
rune(char c) {
data[0] = c;
}
// This constructor needs a string, a position and an offset!
rune(std::string const & s, size_t p, size_t n) {
for (size_t i = 0; i < n; ++i) {
data[i] = s[p + i];
}
}
void swap(rune & other) {
rune t = *this;
*this = other;
other = t;
}
// Output as UTF8!
friend std::ostream & operator <<(std::ostream & output, rune input) {
for (size_t i = 0; i < 4; ++i) {
if (input.data[i] == '\0') {
return output;
}
output << input.data[i];
}
return output;
}
};
エラー処理のアイデア:
C++ で例外を使用するのは好きではありません。私の考えは、コンストラクターが失敗した場合、ルーンを 4 として初期化し'\0'
、ブール演算子を明示的にオーバーロードして、実行の最初のバイトがたまたま'\0'
. シンプルで使いやすい。
それで、考え?意見?異なるアプローチ?
ルーン文字列が多すぎても、少なくともルーンタイプは持っています。小さくて高速にコピーできます。:)