大阪市中央区 システムソフトウェア開発会社

営業時間:平日09:15〜18:15
MENU

C++でC風ライブラリを作る(文字種別編)

著者:高木信尚
公開日:2019/02/06
最終更新日:2019/02/05
カテゴリー:技術情報

高木です。おはようございます。

前回は準備編でしたので、今回からは本格的にライブラリを作っていくことにします。
あくまでもシンプルに気負うことなく作っていきたいので、小難しいことは一切パスです。
作っていくうちにいろいろ欲が出て、凝った仕様や実装にしたくなるところをグッとこらえて、シンプルなものにできたらと思います。

今回作るのは、Cの標準ライブラリでは<ctype.h>で宣言されるisalphaなどの文字種別関連の関数をC++で再設計することにします。

この類いの関数はシンプルなようで、フルスペックにしようと思うと複雑になります。
ロケールの影響を受けるからです。
しかし、実際に使う上ではCロケールだけでかまいませんし、それ以上のことをやられるとかえって邪魔なことのほうが多いんですよ。
たとえば、isdigitは単純に'0'~'9'の場合にtrueを返して欲しいのですが、ローマ数数字だとか丸付き数字だとかでもtrueになってしまうと使い勝手が悪いだけです。
確かにそういう判定をしたいこともあるとは思いますが、その場合は特殊用途の関数を別途用意するほうが嬉しいのです。

また、Cのis~系関数は引数にint型を取ります。
その上で、値が0~UCHAR_MAXまたはEOF以外であれば未定義の動作になります。
文字列中の各文字をひとつずつ判定したい場合には、都度unsigned char型にキャストしなければならず非常に面倒です。

さらに、char型版とwchar_t版では関数名が異なる上に、char16_t型版やchar32_t版がありません。
Cの場合は多重定義ができないので型ごとに別の関数名にするのはしかたがありませんが、C++だとこれはイケてませんね。
というか、次のような処理系の仮定を追加すれば、多重定義する必要すらなさそうです。

  • 各文字型の値のうち、0~0x7fはASCII相当とする。

「ASCII相当」という微妙な表現をしてしまいましたが、ASCIIかASCIIと概ね互換性のある文字コードを仮定するということです。
ここでも小難しい定義を行う気はありません。
このようにしておけば、引数の型をstd::uint_least32_t型にしておくことで多重定義せずに済みそうです。

実際に作ってみたのが下記のコードです。
長いのと、やろうとしていることは自明なのでコメントは省略しています。

<ctype.h>の関数は表引きで実装することが多いのですが、今回は32ビットの文字型を扱うこともあり、表引きにはせず計算で求めるようにしました。
一応、constexprにしていますので、多少は利便性が増したかと思います。
to~系関数はテンプレートで実装してみました。

    上に戻る