使える文字型・データ構造

Mercury::Regexは「どんな文字型でも、どんなデータ構造でも使える」という触れ込みのテンプレートクラスですが、もちろんありとあらゆる型(クラス)やデータ構造を使えるわけではありません。 一定の条件を満たす文字型・データ構造ならばどんな文字型でもデータ構造でも使えるという意味です。 ここでは、文字型とデータ構造がそれぞれ満たすべき条件を説明します。

文字型

文字型は、以下の条件を全て満たす必要があります。 条件は非常に緩く、bool以外のあらゆる組み込み型が使える上に、文字を格納する事を想定して作ったクラスならほとんどのものが使えます。

例えば、次のようなクラスが文字型として使えます。

class character
{
public:
	character(const char ch = 0) { m_ch = ch; }
	bool operator==(const character &rhs) const { return m_ch == rhs.m_ch; }
	bool operator< (const character &rhs) const { return m_ch <  rhs.m_ch; }

	character operator+(const int value) const { return character(static_cast<char>(m_ch + value)); }

private:
	char m_ch;
};

「型同士の比較」および「整数型の加算」を満たす方法として、演算子をオーバーロードする他に、次のようにスカラ型のキャスト演算子を用意する方法もあります。

class character
{
public:
	character(const char ch = 0) { m_ch = ch; }
	operator char(void) const { return m_ch; }

private:
	char m_ch;
};

文字特性を表すクラスは、次のようなメンバ関数を持ちます("mercury/_regex/traits.h" の中で定義されています)。 独自に作成した場合は、basic_regexの2番目の型として指定してください。

template<typename _Char>
class regex_traits
{
public:
	// メタ文字
	static _Char meta_escape          (void); /* エスケープ文字 */
	static _Char meta_disjunction     (void); /* 選言演算子 */
	static _Char meta_repeat0         (void); /* 繰り返し演算子(0回以上) */
	static _Char meta_repeat1         (void); /* 繰り返し演算子(1回以上) */
	static _Char meta_repeat01        (void); /* 繰り返し演算子(0回または1回) */
	static _Char meta_repeat_begin    (void); /* 繰り返し回数指定開始演算子 */
	static _Char meta_repeat_separator(void); /* 繰り返し回数セパレータ */
	static _Char meta_repeat_end      (void); /* 繰り返し回数指定終了演算子 */
	static _Char meta_any             (void); /* 任意の文字にマッチするメタ文字 */
	static _Char meta_set_begin       (void); /* 集合開始演算子 */
	static _Char meta_set_not         (void); /* 補集合演算子 */
	static _Char meta_set_range       (void); /* 集合範囲演算子 */
	static _Char meta_set_end         (void); /* 集合終了演算子 */
	static _Char meta_group_begin     (void); /* グループ化開始演算子 */
	static _Char meta_group_end       (void); /* グループ化終了演算子 */

public:
	// 制御文字
	static _Char cntrl_nul(void); /* 制御文字(NUL) */
	static _Char cntrl_soh(void); /* 制御文字(SOH) */
	static _Char cntrl_stx(void); /* 制御文字(STX) */
	static _Char cntrl_etx(void); /* 制御文字(ETX) */
	static _Char cntrl_eot(void); /* 制御文字(EOT) */
	static _Char cntrl_enq(void); /* 制御文字(ENQ) */
	static _Char cntrl_ack(void); /* 制御文字(ACK) */
	static _Char cntrl_bel(void); /* 制御文字(BEL) */
	static _Char cntrl_bs (void); /* 制御文字(BS ) */
	static _Char cntrl_ht (void); /* 制御文字(HT ) */
	static _Char cntrl_lf (void); /* 制御文字(LF ) */
	static _Char cntrl_vt (void); /* 制御文字(VT ) */
	static _Char cntrl_ff (void); /* 制御文字(FF ) */
	static _Char cntrl_cr (void); /* 制御文字(CR ) */
	static _Char cntrl_so (void); /* 制御文字(SO ) */
	static _Char cntrl_si (void); /* 制御文字(SI ) */
	static _Char cntrl_dle(void); /* 制御文字(DLE) */
	static _Char cntrl_dc1(void); /* 制御文字(DC1) */
	static _Char cntrl_dc2(void); /* 制御文字(DC2) */
	static _Char cntrl_dc3(void); /* 制御文字(DC3) */
	static _Char cntrl_dc4(void); /* 制御文字(DC4) */
	static _Char cntrl_nak(void); /* 制御文字(NAK) */
	static _Char cntrl_syn(void); /* 制御文字(SYN) */
	static _Char cntrl_etb(void); /* 制御文字(ETB) */
	static _Char cntrl_can(void); /* 制御文字(CAN) */
	static _Char cntrl_em (void); /* 制御文字(EM ) */
	static _Char cntrl_sub(void); /* 制御文字(SUB) */
	static _Char cntrl_esc(void); /* 制御文字(ESC) */
	static _Char cntrl_fs (void); /* 制御文字(FS ) */
	static _Char cntrl_gs (void); /* 制御文字(GS ) */
	static _Char cntrl_rs (void); /* 制御文字(RS ) */
	static _Char cntrl_us (void); /* 制御文字(US ) */
	static _Char cntrl_del(void); /* 制御文字(DEL) */

public:
	// 文字クラス
	static const _Char *class_upper             (void); /* 英大文字 */
	static size_t       class_upper_count       (void); /* ↑の文字数 */
	static const _Char *class_lower             (void); /* 英小文字 */
	static size_t       class_lower_count       (void); /* ↑の文字数 */
	static const _Char *class_digit             (void); /* 数字 */
	static size_t       class_digit_count       (void); /* ↑の文字数 */
	static const _Char *class_xdigit            (void); /* 16進数字 */
	static size_t       class_xdigit_count      (void); /* ↑の文字数 */
	static const _Char *class_punct             (void); /* 句読点 */
	static size_t       class_punct_count       (void); /* ↑の文字数 */
	static const _Char *class_blank             (void); /* スペース・タブ */
	static size_t       class_blank_count       (void); /* ↑の文字数 */
	static const _Char *class_space             (void); /* 空白 */
	static size_t       class_space_count       (void); /* ↑の文字数 */
	static const _Char *class_cntrl             (void); /* 制御文字 */
	static size_t       class_cntrl_count       (void); /* ↑の文字数 */
	static const _Char *class_graph_invert      (void); /* 印字可能文字の補集合 */
	static size_t       class_graph_invert_count(void); /* ↑の文字数 */
	static const _Char *class_print_invert      (void); /* スペースを含む印字可能文字の補集合 */
	static size_t       class_print_invert_count(void); /* ↑の文字数 */

public:
	/*
	 * chが数字の場合、整数値に変換してその数値を返す(変換できなければ-1を返す)
	 */
	static int number(const _Char &ch);

	/*
	 * beginからendまでを文字列とみなし、その文字列に含まれている数字を10進数とみなして整数値で返す。
	 * 先頭文字が数字でなければ-1を返す。
	 * 数字以外の文字が現れたら、その文字が現れる前までの文字列を整数値に変換して走査終了。
	 * beginは、走査終了時点(数字以外の文字またはend)まで移動させる。
	 */
	template<typename _ConstIterator>
	static int number(_ConstIterator &begin, const _ConstIterator &end);

public:
	/* コードポイントがchより1つ大きい文字を返す */
	static _Char next(const _Char &ch);

	/*
	 * beginからendまでを文字列とみなし、その文字列に含まれている正規表現の区分を返す。
	 * 区分および返す値は以下の通り。
	 *  区分         返す値
	 *  [:upper:]    CHARCLASS_UPPER
	 *  [:lower:]    CHARCLASS_LOWER
	 *  [:alpha:]    CHARCLASS_ALPHA
	 *  [:digit:]    CHARCLASS_DIGIT
	 *  [:alnum:]    CHARCLASS_ALNUM
	 *  [:xdigit:]   CHARCLASS_XDIGIT
	 *  [:punct:]    CHARCLASS_PUNCT
	 *  [:blank:]    CHARCLASS_BLANK
	 *  [:space:]    CHARCLASS_SPACE
	 *  [:cntrl:]    CHARCLASS_CNTRL
	 *  [:graph:]    CHARCLASS_GRAPH
	 *  [:print:]    CHARCLASS_PRINT
	 * 文字列の先頭に区分が現れなかった場合は(たとえ途中に現れても)CHARCLASS_NONEを返す。
	 * beginは、走査終了時点まで移動させる。
	 */
	template<typename _ConstIterator>
	static CHARCLASS get_charclass(_ConstIterator &begin, const _ConstIterator &end);
};

データ構造

文字列としてのデータ構造は、以下の条件のいずれか満たす必要があります。 文字型に比べると厳しい条件ですが、STLのコンテナに準拠した仕様となっているので戸惑うことはないと思います。

STLではstringやvectorはもちろん、list, deque等も使えます。 setはコンパイルエラーにはなりませんが、データを格納した時点で順序付けられている(=ソートされている)ので、文字列としては使えません。

begin(), end()を持っている場合はオブジェクトをそのままコンストラクタ等に入れればいいのですが、イテレータしか持っていない場合は先頭と末尾の1つ先のイテレータをこの順番で指定する必要があります。 実際のコードは使い方を参照してください。