C++Builderで正規表現を利用する場合についてのメモ。
文字列処理を行うアプリケーションを作る時、正規表現を使えたら便利ですよね。私自身、正規表現を扱いだしたのが最近なので未熟なのですが、webで情報を集めてBCBで正規表現を扱う方法をまとめてみました。
今のところマッチングについての情報のみ。サンプルは出来るところから手をつけたのでそれぞれの方法で動作が若干(?)異なります。置換については追々。
調べてみると色々方法があって、それぞれ特徴があるようです。方言や制限などもあるようなので用途によって使い分けが必要なのかも。
目次
TRegexpクラスを使う
- 探した方が悪いのかヘルプに載ってないです。webで情報を集めてみました。
- 簡単に使えますが他と比べて低機能です。
- ShiftJISに対応しています。
環境用意
#include <regexp.h>
標準で付いているregexp.hをインクルードすることで使用可能となります。
検索準備
TRegex x("ab?");
パターン文字列を引数にしてオブジェクト生成します。
検索
size_t len; int p = x.find(text, &len, 0);
findメソッドで検索を行います。findメソッドのプロトタイプは、
size_t find(const string& s, size_t* len, size_t start=0) const;
こんな感じです。第1引数に検索対象となる文字列。第2引数にマッチングした文字列長を受け取る変数へのポインタ、第3引数はサーチ開始位置となってます。
見つからない場合は、戻り値-1。長さゼロを返します。
その他
statusメソッドは、与えられた正規表現が正しいかどうかを返します。以下、戻り値の定義。
enum StatVal { OK=0, ILLEGAL, NOMEMORY, TOOLONG };
正規表現
特殊文字
. [ ] - ^ * ? + $
コントロール文字
\b | バックスペース |
\e | Esc |
\f | 改ページ |
\n | 改行 |
\r | 復帰 |
\t | タブ |
\xddd | 16 進 0xddd に対する文字 |
\^x | X に対するコントロールコード(例: \^c は ctrl-c) |
POSIX互換関数を使う
- 標準的な存在らしいので資料も多く見つかります。
環境用意
#include <pcreposi.h>
標準で付いてくるpcreposi.hをインクルードすることで使用可能となります。
検索準備
regex_t regex; regmatch_t match[10]; regcomp(®ex, "<(.*?)>", 0);
- regex_tはregexのパターンバッファ。
- regmatch_tはマッチした場所の情報を格納する配列です。予め確保しておく必要があります。
- regcomp関数で正規表現をコンパイルします。第3引数は未調査です。
検索
int ret = regexec(®ex, text, 10, match, 0);
第2引数は検索対象テキストです。第3引数はマッチ情報格納用配列のMAX値。第4引数はマッチ情報格納用配列、第5引数は未調査です。
戻り値はヘッダファイルで定義されたenum値が入ります。
match[0]には最初にマッチした全体位置の情報が格納されます。match[1]以降はグループ( )に一致した文字列の位置情報が格納されます。利用されなかった配列には(-1,-1)が格納されます。
後処理
regfree(®ex);
としてパターンバッファを解放します。
その他
正規表現にミスがあるかどうかはregerror関数で確認できます。
BREGEXP.DLLを使う
- BREGEXP.DLLはPerl5 互換の正規表現(日本語対応)をサポートするDLLです。
- 武内 修さん作のDelphi用BRegExp ユニットがありますが、C++Builderで使ってみようとしたところ色々と面倒な問題があり正直お勧めできません。
- ここではpmansatoさん作のCBRegExpクラスを使ってみることにします。
環境準備
- cbregexp.lzhを入手します。
- CBRegExp.cpp/.h ファイルをプロジェクトに追加します。
- 次に利用するソースファイルを開き「ファイル>ユニットを使う」により使用可能状態にします。(要するにヘッダファイルをインクルードする)
- BREGEXP.DLLをパスの通った場所に置きます。
この時点でビルドできていれば準備OKです。
検索準備
CBRegExp *exp = new CBRegExp(); TExecFlags flag; flag << efKanji << efIgnoreCase << efMultiLine; exp->Modifier = flag;
オブジェクトの生成とフラグの設定を行います。漢字対応やマルチラインの文字列として判定するかなどの設定を行います。
検索
int Match(AnsiString Pattern, AnsiString Target, int* Length, int Pos);
Matchメソッドでマッチングを行います。第1引数は正規表現パターン。第2引数は対象文字列、第3引数はマッチした文字列長を返すint型変数へのポインタ、第4引数は検索開始位置です。
戻り値は見つかった文字列の先頭位置を返します。見つからなかった場合は -1 を返します。
後始末
delete exp;
newでオブジェクトを生成しているのでdeleteを忘れずに。
その他
時々例外が発生するのですが原因がいまいち特定できません。何か気づいた方、教えてください。
boost::regexを使う
boostライブラリにも正規表現が存在します。こちらでは文字列型としてSTLのstring型やwstring型を利用します。
ShiftJISは非対応ですが、ワイド文字列(wstring)を使えます。
標準ライブラリではないので自分でインストールする必要があります。BDS2006の場合はこちらが参考になるかと。
環境準備
- BoostC++ライブラリをインストールします。
#include <string> #include <boost/regex.hpp>
regex.hppをインクルードします。BoostC++のRegexでは文字列としてSTLのstringテンプレートを使用しますのでstringもインクルードします。
using namespace std; using namespace boost;
必要に応じてネームスペース宣言もしておきます。
検索準備
ワイド文字列を扱うか否かで型名が異なります。
日本語を使う場合
wregex exp(L"<.*?>"); wsmatch result;
日本語を使わない場合
regex exp("<.*?>"); smatch result;
検索
regex_serch()やregex_match()を使って検索し、結果をsmatch型/wsmatch型で受け取る流れになります。
regex_serch()やregex_match()については引数に様々なバリエーションがあって私も良くわかりません。
その他
VCLと組み合わせて使うとワイド文字列とマルチバイト文字列とを行ったり来たりすることになるのが面倒ですね。
サンプル
下図のようなプログラムを作ります。
正規表現を入れて、各ボタンで検索。上のメモには検索対象、下のメモには結果を表示します。
サンプルのソース
参考リンク
- C++Builderで正規表現を使うには
- BREGEXP.DLL を使う
- BREGEXP DLL
- 正規表現ライブラリ
- 正規表現 TRegexp の使用例
- 正規表現に関する雑記
- よよょ日記-TRegexp クラス
- Turbo C++ 4.0J のヘルプの内容
- POSIX正規表現 regex.h
- regex - POSIX.2 正規表現
- BREGEXP.DLLの使い方
- BREGEXP.DLLのDelphi用ライブラリ
参考図書
- 正規表現ケーススタディブック (単行本) ハーシー (著)
- Boost C++ Libraryプログラミング 稲葉 一浩
【amazon】