C++で正規表現 (4)

Tatsuo Baba氏のBREGEXPでもやってみた。Baba氏のライブラリにはVB5/6の頃にはお世話になった。手軽に色々やりたいときに便利である。
bregexp.lzhに含まれるstruct bregexpの宣言は古いようで、parap以下のメンバーが含まれていない。Linux版やwebに載っている構造体の通りに修正する必要がある。

注意点としては、BREGEXPではライブラリに渡す正規表現が"フラグ/正規表現/"という形式なので、HTMLのタグの終わりを検出したい場合などはエスケープ(あるいはエスケープ文字の変更)が必要になる。

BREGEXP.H(の構造体の修正版)


typedef struct bregexp {
const char *outp; /* result string start ptr */
const char *outendp; /* result string end ptr */
const int splitctr; /* split result counter */
const char **splitp; /* split result pointer ptr */
int rsv1; /* reserved for external use */
char *parap; /* parameter start ptr ie. "s/xxxxx/yy/gi" */
char *paraendp; /* parameter end ptr */
char *transtblp; /* translate table ptr */
char **startp; /* match string start ptr */
char **endp; /* match string end ptr */
int nparens; /* number of parentheses */
} BREGEXP;
(略)
regex.h

#include
#include

struct bregexp;

class CRegex {
bregexp *m_BREGEXP;
std::vector m_Results;
void Reset( void ) { m_Results.empty(); }

public:
CRegex( void ) : m_BREGEXP( NULL ) { }
~CRegex();
int Match( const char *pszExpression, const char *pszTarget );
bool GetPosition( unsigned int nIndex, int &nStart, int &nEnd ) const;
std::string GetResult( unsigned int nIndex ) const;
};

regex.cpp

#include "regex.h"
#include "BREGEXP.h"

// VC++の場合、自動リンク
#ifdef _MSC_VER
#pragma comment(lib, "bregexp.lib")
#endif // _MSC_VER

CRegex::~CRegex()
{
if ( m_BREGEXP ) {
BRegfree( m_BREGEXP );
}
}

// 一致判定
// pszExpression: Perl正規表現文字列 (ex. "/foo.*/")
// pszTarget: 検索対象文字列
// 戻り値: 1以上なら一致
int CRegex::Match( const char *pszExpression, const char *pszTarget )
{
Reset(); // 検索結果のリセット
char msg[256];
int nResult = BMatch( const_cast(pszExpression),
const_cast(pszTarget),
const_cast(pszTarget + strlen(pszTarget)),
&m_BREGEXP, msg );
if ( nResult < 1 ) {
// エラーもしくは一致せず
return nResult;
}

int i;
for ( i = 0; i <= m_BREGEXP->nparens; ++i ) {
// 結果をベクターに保存しておく
m_Results.push_back( std::string( m_BREGEXP->startp[i],
m_BREGEXP->endp[i] - m_BREGEXP->startp[i] ) );
// ポインタをオフセットで上書きする
m_BREGEXP->startp[i] = (char *)( m_BREGEXP->startp[i] - pszTarget );
m_BREGEXP->endp[i] = (char *)( m_BREGEXP->endp[i] - pszTarget );
}
return m_BREGEXP->nparens + 1;
}

// 一致した先頭位置と終端位置を取得(終端-先頭=長さ)
bool CRegex::GetPosition( unsigned int nIndex, int &nStart, int &nEnd ) const
{
if ( nIndex >= m_Results.size() ) {
return false;
}
nStart = (int)m_BREGEXP->startp[ nIndex ];
nEnd = (int)m_BREGEXP->endp[ nIndex ];
return true;
}

// 一致した文字列を取得
std::string CRegex::GetResult( unsigned int nIndex ) const
{
if ( nIndex >= m_Results.size() ) {
return "";
}
return m_Results[ nIndex ];
}

呼び出しサンプル(1〜3とは少し異なる)

CRegex Regex;
int nResults = Regex.Match( "/(abc)(def)ghi/", "abcdefghijkl" );
std::cout << nResults << ", " << Regex.GetResult(0) << ", ";
std::cout << Regex.GetResult(1) << ", " << Regex.GetResult(2) << std::endl;