C++で正規表現 (1)

しばしばC++正規表現検索の必要に迫られるので、少し試してみた。
(自分が)手軽に使えるように CRegex というラッパーを作成した。

使い方は


CRegex Regex( "(abc)(def)ghi" );
int nResults = Regex.Match( "abcdefghijkl" );
std::cout << nResults << ", " << Regex.GetResult(0) << ", " << Regex.GetResult(1) << ", " << Regex.GetResult(2) << std::endl;
という感じで、戻り値が1以上なら一致文字列あり。
インデックス0に全体が、インデックス1以降に後方参照文字列($1、$2、...)が入る。上記の場合、結果は

3, abcdefghi, abc, def
となる。

まずは http://www.nakka.com/lib/regex について。
Shift-JIS用らしいのだが、UTF-8の少々長い文字列を食わせたらスタックオーバーフローでお亡くなりになってしまった。ソースは短いので、学習用としては良いかも。


#include "regex.h"

class CRegex {
REGE_NFA *m_nfa;
REGE_REFER *m_rf;
int m_nResult;
std::vector m_Results;
void Reset( void );

public:
CRegex( const char *pszExpression );
~CRegex();
int Match( const char *pszTarget, bool bIgnoreCase = false );
bool GetPosition( int nIndex, int &nStart, int &nEnd ) const;
std::string GetResult( int nIndex ) const;
};

// コンストラクタでコンパイル
CRegex::CRegex( const char *pszExpression )
: m_rf( NULL )
{
m_nfa = rege_compile( pszExpression );
}

CRegex::~CRegex()
{
Reset();
if ( m_nfa ) {
free_nfa( m_nfa );
}
}

// 検索結果のリセット
void CRegex::Reset( void )
{
m_Results.empty();
if ( m_rf ) {
free_refer( m_rf );
m_rf = NULL;
}
}

// 一致判定(pszTarget: 検索対象文字列、bIgnoreCase == true: 大文字小文字無視)
int CRegex::Match( const char *pszTarget, bool bIgnoreCase )
{
if ( m_nfa == NULL ) {
return -1;
}
Reset();
m_nResult = reg_match( m_nfa, pszTarget, &m_rf, bIgnoreCase );
int i;
for ( i = 0; i < m_nResult; ++i ) {
// 結果はポインタだけなので、ベクターに保存しておく
m_Results.push_back( std::string( m_rf[i].st, m_rf[i].en - m_rf[i].st ) );
// ポインタをオフセットで上書きする
m_rf[i].st = (char *)( m_rf[i].st - pszTarget );
m_rf[i].en = (char *)( m_rf[i].en - pszTarget );
}
return m_nResult;
}

// 一致した先頭位置と終端位置を取得(終端-先頭=長さ)
bool CRegex::GetPosition( int nIndex, int &nStart, int &nEnd ) const
{
if ( nIndex < 0 || nIndex >= m_nResult ) {
return false;
}
nStart = (int)m_rf[ nIndex ].st;
nEnd = (int)m_rf[ nIndex ].en;
return true;
}

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