介绍一个不错的正则表达式的类

deelx.h文件为:

// deelx.h
//
// DEELX Regular Expression Engine (v1.2)
//
// Copyright 2006 (c) RegExLab.com
// All Rights Reserved.
//
// http://www.regexlab.com/deelx/
//
// Author: 史寿伟 (sswater shi)
// sswater@gmail.com
//
// $Revision: 680 $
//

#ifndef __DEELX_REGEXP__H__
#define __DEELX_REGEXP__H__

#include <memory.h>
#include <ctype.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>

extern "C" {
 typedef int (*POSIX_FUNC)(int);
 int isblank(int c);
}

//
// Data Reference
//
template <class ELT> class CBufferRefT
{
public:
 CBufferRefT(const ELT * pcsz, int length);
 CBufferRefT(const ELT * pcsz);

public:
 int nCompare      (const ELT * pcsz) const;
 int nCompareNoCase(const ELT * pcsz) const;
 int  Compare      (const ELT * pcsz) const;
 int  CompareNoCase(const ELT * pcsz) const;
 int  Compare      (const CBufferRefT <ELT> &) const;
 int  CompareNoCase(const CBufferRefT <ELT> &) const;

 ELT At          (int nIndex, ELT def = 0) const;
 ELT operator [] (int nIndex) const;

 const ELT * GetBuffer() const;
 int GetSize() const;

public:
 virtual ~CBufferRefT();

// Content
protected:
 const ELT * m_pRef;
 int         m_nSize;
};

//
// Implemenation
//
template <class ELT> CBufferRefT <ELT> :: CBufferRefT(const ELT * pcsz, int length)
{
 m_pRef  = pcsz;
 m_nSize = length;
}

template <class ELT> CBufferRefT <ELT> :: CBufferRefT(const ELT * pcsz)
{
 m_pRef  = pcsz;
 m_nSize = 0;

 if(pcsz != 0) while(m_pRef[m_nSize] != 0) m_nSize ++;
}

template <class ELT> int CBufferRefT <ELT> :: nCompare(const ELT * pcsz) const
{
 for(int i=0; i<m_nSize; i++)
 {
  if(m_pRef[i] != pcsz[i])
   return m_pRef[i] - pcsz[i];
 }

 return 0;
}

template <class ELT> int CBufferRefT <ELT> :: nCompareNoCase(const ELT * pcsz) const
{
 for(int i=0; i<m_nSize; i++)
 {
  if(m_pRef[i] != pcsz[i])
  {
   if(toupper((int)m_pRef[i]) != toupper((int)pcsz[i]))
    return m_pRef[i] - pcsz[i];
  }
 }

 return 0;
}

template <class ELT> inline int CBufferRefT <ELT> :: Compare(const ELT * pcsz) const
{
 return nCompare(pcsz) ? 1 : (int)pcsz[m_nSize];
}

template <class ELT> inline int CBufferRefT <ELT> :: CompareNoCase(const ELT * pcsz) const
{
 return nCompareNoCase(pcsz) ? 1 : (int)pcsz[m_nSize];
}

template <class ELT> inline int CBufferRefT <ELT> :: Compare(const CBufferRefT <ELT> & cref) const
{
 return m_nSize == cref.m_nSize ? nCompare(cref.GetBuffer()) : 1;
}

template <class ELT> inline int CBufferRefT <ELT> :: CompareNoCase(const CBufferRefT <ELT> & cref) const
{
 return m_nSize == cref.m_nSize ? nCompareNoCase(cref.GetBuffer()) : 1;
}

template <class ELT> inline ELT CBufferRefT <ELT> :: At(int nIndex, ELT def) const
{
 return nIndex >= m_nSize ? def : m_pRef[nIndex];
}

template <class ELT> inline ELT CBufferRefT <ELT> :: operator [] (int nIndex) const
{
 return nIndex >= m_nSize ? 0 : m_pRef[nIndex];
}

template <class ELT> const ELT * CBufferRefT <ELT> :: GetBuffer() const
{
 static const ELT _def[] = {0}; return m_pRef ? m_pRef : _def;
}

template <class ELT> inline int CBufferRefT <ELT> :: GetSize() const
{
 return m_nSize;
}

template <class ELT> CBufferRefT <ELT> :: ~CBufferRefT()
{
}

//
// Data Buffer
//
template <class ELT> class CBufferT : public CBufferRefT <ELT>
{
public:
 CBufferT(const ELT * pcsz, int length);
 CBufferT(const ELT * pcsz);
 CBufferT();

public:
 ELT & operator [] (int nIndex);
 const ELT & operator [] (int nIndex) const;
 void  Append(const ELT * pcsz, int length, int eol = 0);
 void  Append(ELT el, int eol = 0);

public:
 void  Push(ELT   el);
 int   Pop (ELT & el);
 int   Peek(ELT & el) const;

public:
 const ELT * GetBuffer() const;
 ELT * GetBuffer();
 ELT * Detach();
 void  Release();
 void  Prepare(int index, int fill = 0);
 void  Restore(int size);

public:
 virtual ~CBufferT();

// Content
protected:
 ELT * m_pBuffer;
 int   m_nMaxLength;
};

//
// Implemenation
//
template <class ELT> CBufferT <ELT> :: CBufferT(const ELT * pcsz, int length) : CBufferRefT <ELT> (0, length)
{
 m_nMaxLength = CBufferRefT <ELT> :: m_nSize + 1;

 CBufferRefT <ELT> :: m_pRef = m_pBuffer = (ELT *) malloc(sizeof(ELT) * m_nMaxLength);
 memcpy(m_pBuffer, pcsz, sizeof(ELT) * CBufferRefT <ELT> :: m_nSize);
 m_pBuffer[CBufferRefT <ELT> :: m_nSize] = 0;
}

template <class ELT> CBufferT <ELT> :: CBufferT(const ELT * pcsz) : CBufferRefT <ELT> (pcsz)
{
 m_nMaxLength = CBufferRefT <ELT> :: m_nSize + 1;

 CBufferRefT <ELT> :: m_pRef = m_pBuffer = (ELT *) malloc(sizeof(ELT) * m_nMaxLength);
 memcpy(m_pBuffer, pcsz, sizeof(ELT) * CBufferRefT <ELT> :: m_nSize);
 m_pBuffer[CBufferRefT <ELT> :: m_nSize] = 0;
}

template <class ELT> CBufferT <ELT> :: CBufferT() : CBufferRefT <ELT> (0, 0)
{
 m_nMaxLength = 0;
 m_pBuffer    = 0;
}

template <class ELT> inline ELT & CBufferT <ELT> :: operator [] (int nIndex)
{
 return m_pBuffer[nIndex];
}

template <class ELT> inline const ELT & CBufferT <ELT> :: operator [] (int nIndex) const
{
 return m_pBuffer[nIndex];
}

template <class ELT> void CBufferT <ELT> :: Append(const ELT * pcsz, int length, int eol)
{
 int nNewLength = m_nMaxLength;

 // Check length
 if(nNewLength < 8)
  nNewLength = 8;

 if(CBufferRefT <ELT> :: m_nSize + length + eol > nNewLength)
  nNewLength *= 2;

 if(CBufferRefT <ELT> :: m_nSize + length + eol > nNewLength)
 {
  nNewLength  = CBufferRefT <ELT> :: m_nSize + length + eol + 11;
  nNewLength -= nNewLength % 8;
 }

 // Realloc
 if(nNewLength > m_nMaxLength)
 {
  CBufferRefT <ELT> :: m_pRef = m_pBuffer = (ELT *) realloc(m_pBuffer, sizeof(ELT) * nNewLength);
  m_nMaxLength = nNewLength;
 }

 // Append
 memcpy(m_pBuffer + CBufferRefT <ELT> :: m_nSize, pcsz, sizeof(ELT) * length);
 CBufferRefT <ELT> :: m_nSize += length;

 if(eol > 0) m_pBuffer[CBufferRefT <ELT> :: m_nSize] = 0;
}

template <class ELT> inline void CBufferT <ELT> :: Append(ELT el, int eol)
{
 Append(&el, 1, eol);
}

template <class ELT> void CBufferT <ELT> :: Push(ELT el)
{
 // Realloc
 if(CBufferRefT <ELT> :: m_nSize >= m_nMaxLength)
 {
  int nNewLength = m_nMaxLength * 2;
  if( nNewLength < 8 ) nNewLength = 8;

  CBufferRefT <ELT> :: m_pRef = m_pBuffer = (ELT *) realloc(m_pBuffer, sizeof(ELT) * nNewLength);
  m_nMaxLength = nNewLength;
 }

 // Append
 m_pBuffer[CBufferRefT <ELT> :: m_nSize++] = el;
}

template <class ELT> inline int CBufferT <ELT> :: Pop(ELT & el)
{
 if(CBufferRefT <ELT> :: m_nSize > 0)
 {
  el = m_pBuffer[--CBufferRefT <ELT> :: m_nSize];
  return 1;
 }
 else
 {
  return 0;
 }
}

template <class ELT> inline int CBufferT <ELT> :: Peek(ELT & el) const
{
 if(CBufferRefT <ELT> :: m_nSize > 0)
 {
  el = m_pBuffer[CBufferRefT <ELT> :: m_nSize - 1];
  return 1;
 }
 else
 {
  return 0;
 }
}

template <class ELT> const ELT * CBufferT <ELT> :: GetBuffer() const
{
 static const ELT _def[] = {0}; return m_pBuffer ? m_pBuffer : _def;
}

template <class ELT> ELT * CBufferT <ELT> :: GetBuffer()
{
 static const ELT _def[] = {0}; return m_pBuffer ? m_pBuffer : (ELT *)_def;
}

template <class ELT> ELT * CBufferT <ELT> :: Detach()
{
 ELT * pBuffer = m_pBuffer;

 CBufferRefT <ELT> :: m_pRef  = m_pBuffer    = 0;
 CBufferRefT <ELT> :: m_nSize = m_nMaxLength = 0;

 return pBuffer;
}

template <class ELT> void CBufferT <ELT> :: Release()
{
 ELT * pBuffer = Detach();

 if(pBuffer != 0) free(pBuffer);
}

template <class ELT> void CBufferT <ELT> :: Prepare(int index, int fill)
{
 int nNewSize = index + 1;

 // Realloc
 if(nNewSize > m_nMaxLength)
 {
  int nNewLength = m_nMaxLength;

  if( nNewLength < 8 )
   nNewLength = 8;

  if( nNewSize > nNewLength )
   nNewLength *= 2;

  if( nNewSize > nNewLength )
  {
   nNewLength  = nNewSize + 11;
   nNewLength -= nNewLength % 8;
  }

  CBufferRefT <ELT> :: m_pRef = m_pBuffer = (ELT *) realloc(m_pBuffer, sizeof(ELT) * nNewLength);
  m_nMaxLength = nNewLength;
 }

 // size
 if( CBufferRefT <ELT> :: m_nSize < nNewSize )
 {
  memset(m_pBuffer + CBufferRefT <ELT> :: m_nSize, fill, sizeof(ELT) * (nNewSize - CBufferRefT <ELT> :: m_nSize));
  CBufferRefT <ELT> :: m_nSize = nNewSize;
 }
}

template <class ELT> inline void CBufferT <ELT> :: Restore(int size)
{
 CBufferRefT <ELT> :: m_nSize = size;
}

template <class ELT> CBufferT <ELT> :: ~CBufferT()
{
 if(m_pBuffer != 0) free(m_pBuffer);
}

//
// Context
//
class CContext
{
public:
 CBufferT <int> m_stack;
 CBufferT <int> m_capturestack, m_captureindex;

public:
 int    m_nCurrentPos;
 int    m_nBeginPos;
 int    m_nLastBeginPos;
 int    m_nParenZindex;

 void * m_pMatchString;
 int    m_pMatchStringLength;
};

//
// Interface
//
class ElxInterface
{
public:
 virtual int Match    (CContext * pContext) const = 0;
 virtual int MatchNext(CContext * pContext) const = 0;

public:
 virtual ~ElxInterface() {};
};

//
// Alternative
//
template <int x> class CAlternativeElxT : public ElxInterface
{
public:
 int Match    (CContext * pContext) const;
 int MatchNext(CContext * pContext) const;

public:
 CAlternativeElxT();

public:
 CBufferT <ElxInterface *> m_elxlist;
};

typedef CAlternativeElxT <0> CAlternativeElx;

//
// Assert
//
template <int x> class CAssertElxT : public ElxInterface
{
public:
 int Match    (CContext * pContext) const;
 int MatchNext(CContext * pContext) const;

public:
 CAssertElxT(ElxInterface * pelx, int byes = 1);

public:
 ElxInterface * m_pelx;
 int m_byes;
};

typedef CAssertElxT <0> CAssertElx;

//
// Back reference elx
//
template <class CHART> class CBackrefElxT : public ElxInterface
{
public:
 int Match    (CContext * pContext) const;
 int MatchNext(CContext * pContext) const;

public:
 CBackrefElxT(int nnumber, int brightleft, int bignorecase);

public:
 int m_nnumber;
 int m_brightleft;
 int m_bignorecase;

 CBufferT <CHART> m_szNamed;
};

//
// Implementation
//
template <class CHART> CBackrefElxT <CHART> :: CBackrefElxT(int nnumber, int brightleft, int bignorecase)
{
 m_nnumber     = nnumber;
 m_brightleft  = brightleft;
 m_bignorecase = bignorecase;
}

template <class CHART> int CBackrefElxT <CHART> :: Match(CContext * pContext) const
{
 // check number, for named
 if( m_nnumber < 0 || m_nnumber >= pContext->m_captureindex.GetSize() ) return 0;

 int index = pContext->m_captureindex[m_nnumber];
 if( index < 0 ) return 0;

 // check enclosed
 int pos1 = pContext->m_capturestack[index + 1];
 int pos2 = pContext->m_capturestack[index + 2];

 if( pos2 < 0 ) pos2 = pContext->m_nCurrentPos;

 // info
 int lpos = pos1 < pos2 ? pos1 : pos2;
 int rpos = pos1 < pos2 ? pos2 : pos1;
 int slen = rpos - lpos;

 const CHART * pcsz = (const CHART *)pContext->m_pMatchString;
 int npos = pContext->m_nCurrentPos;
 int tlen = pContext->m_pMatchStringLength;

 // compare
 int bsucc;
 CBufferRefT <CHART> refstr(pcsz + lpos, slen);

 if( m_brightleft )
 {
  if(npos < slen)
   return 0;

  if(m_bignorecase)
   bsucc = ! refstr.nCompareNoCase(pcsz + (npos - slen));
  else
   bsucc = ! refstr.nCompare      (pcsz + (npos - slen));

  if( bsucc )
  {
   pContext->m_stack.Push(npos);
   pContext->m_nCurrentPos -= slen;
  }
 }
 else
 {
  if(npos + slen > tlen)
   return 0;

  if(m_bignorecase)
   bsucc = ! refstr.nCompareNoCase(pcsz + npos);
  else
   bsucc = ! refstr.nCompare      (pcsz + npos);

  if( bsucc )
  {
   pContext->m_stack.Push(npos);
   pContext->m_nCurrentPos += slen;
  }
 }

 return bsucc;
}

template <class CHART> int CBackrefElxT <CHART> :: MatchNext(CContext * pContext) const
{
 int npos = 0;

 pContext->m_stack.Pop(npos);
 pContext->m_nCurrentPos = npos;

 return 0;
}

// RCHART
#ifndef RCHART
 #define RCHART(ch) ((CHART)ch)
#endif

// BOUNDARY_TYPE
enum BOUNDARY_TYPE
{
 BOUNDARY_FILE_BEGIN, // begin of whole text
 BOUNDARY_FILE_END  , // end of whole text
 BOUNDARY_FILE_END_N, // end of whole text, or before newline at the end
 BOUNDARY_LINE_BEGIN, // begin of line
 BOUNDARY_LINE_END  , // end of line
 BOUNDARY_WORD_BEGIN, // begin of word
 BOUNDARY_WORD_END  , // end of word
 BOUNDARY_WORD_EDGE
};

//
// Boundary Elx
//
template <class CHART> class CBoundaryElxT : public ElxInterface
{
public:
 int Match    (CContext * pContext) const;
 int MatchNext(CContext * pContext) const;

public:
 CBoundaryElxT(int ntype, int byes = 1);

protected:
 static int IsWordChar(CHART ch);

public:
 int m_ntype;
 int m_byes;
};

//
// Implementation
//
template <class CHART> CBoundaryElxT <CHART> :: CBoundaryElxT(int ntype, int byes)
{
 m_ntype = ntype;
 m_byes  = byes;
}

template <class CHART> int CBoundaryElxT <CHART> :: Match(CContext * pContext) const
{
 const CHART * pcsz  = (const CHART *)pContext->m_pMatchString;
 int npos = pContext->m_nCurrentPos;
 int tlen = pContext->m_pMatchStringLength;

 CHART chL = npos > 0    ? pcsz[npos - 1] : 0;
 CHART chR = npos < tlen ? pcsz[npos    ] : 0;

 int bsucc = 0;

 switch(m_ntype)
 {
 case BOUNDARY_FILE_BEGIN:
  bsucc = (npos <= 0);
  break;

 case BOUNDARY_FILE_END:
  bsucc = (npos >= tlen);
  break;

 case BOUNDARY_FILE_END_N:
  bsucc = (npos >= tlen) || (pcsz[tlen-1] == RCHART('/n') && (npos == tlen-1 || (pcsz[tlen-2] == RCHART('/r') && npos == tlen-2)));
  break;

 case BOUNDARY_LINE_BEGIN:
  bsucc = (npos <= 0   ) || (chL == RCHART('/n')) || ((chL == RCHART('/r')) && (chR != RCHART('/n')));
  break;

 case BOUNDARY_LINE_END:
  bsucc = (npos >= tlen) || (chR == RCHART('/r')) || ((chR == RCHART('/n')) && (chL != RCHART('/r')));
  break;

 case BOUNDARY_WORD_BEGIN:
  bsucc = ! IsWordChar(chL) &&   IsWordChar(chR);
  break;

 case BOUNDARY_WORD_END:
  bsucc =   IsWordChar(chL) && ! IsWordChar(chR);
  break;

 case BOUNDARY_WORD_EDGE:
  bsucc =   IsWordChar(chL) ?  ! IsWordChar(chR) : IsWordChar(chR);
  break;
 }

 return m_byes ? bsucc : ! bsucc;
}

template <class CHART> int CBoundaryElxT <CHART> :: MatchNext(CContext *) const
{
 return 0;
}

template <class CHART> inline int CBoundaryElxT <CHART> :: IsWordChar(CHART ch)
{
 return (ch >= RCHART('A') && ch <= RCHART('Z')) || (ch >= RCHART('a') && ch <= RCHART('z')) || (ch >= RCHART('0') && ch <= RCHART('9')) || (ch == RCHART('_'));
}

//
// Bracket
//
template <class CHART> class CBracketElxT : public ElxInterface 
{
public:
 int Match    (CContext * pContext) const;
 int MatchNext(CContext * pContext) const;

public:
 CBracketElxT(int nnumber, int bright);
 int CheckCaptureIndex(int & index, CContext * pContext) const;

public:
 int m_nnumber;
 int m_bright;

 CBufferT <CHART> m_szNamed;
};

template <class CHART> CBracketElxT <CHART> :: CBracketElxT(int nnumber, int bright)
{
 m_nnumber = nnumber;
 m_bright  = bright;
}

template <class CHART> inline int CBracketElxT <CHART> :: CheckCaptureIndex(int & index, CContext * pContext) const
{
 if( index >= pContext->m_capturestack.GetSize() )
  index  = pContext->m_capturestack.GetSize() - 4;

 while(index >= 0)
 {
  if(pContext->m_capturestack[index] == m_nnumber)
  {
   return 1;
  }

  index -= 4;
 }


 return 0;
}

//
// capturestack[index+0] => Group number
// capturestack[index+1] => Capture start pos
// capturestack[index+2] => Capture end pos
// capturestack[index+3] => Capture enclose z-index, zindex<0 means inner group with same name
//
template <class CHART> int CBracketElxT <CHART> :: Match(CContext * pContext) const
{
 // check, for named
 if(m_nnumber < 0) return 0;

 if( ! m_bright )
 {
  pContext->m_captureindex.Prepare(m_nnumber, -1);
  int index = pContext->m_captureindex[m_nnumber];

  // check
  if(CheckCaptureIndex(index, pContext) && pContext->m_capturestack[index+2] < 0)
  {
   pContext->m_capturestack[index+3] --;
   return 1;
  }

  // save
  pContext->m_captureindex[m_nnumber] = pContext->m_capturestack.GetSize();

  pContext->m_capturestack.Push(m_nnumber);
  pContext->m_capturestack.Push(pContext->m_nCurrentPos);
  pContext->m_capturestack.Push(-1);
  pContext->m_capturestack.Push( 0); // z-index
 }
 else
 {
  // check
  int index = pContext->m_captureindex[m_nnumber];

  if(CheckCaptureIndex(index, pContext))
  {
   if(pContext->m_capturestack[index + 3] < 0) // check inner group with same name
   {
    pContext->m_capturestack[index + 3] ++;
    return 1;
   }

   // save
   pContext->m_capturestack[index + 2] = pContext->m_nCurrentPos;
   pContext->m_capturestack[index + 3] = pContext->m_nParenZindex ++;
  }
 }

 return 1;
}

template <class CHART> int CBracketElxT <CHART> :: MatchNext(CContext * pContext) const
{
 int index = pContext->m_captureindex[m_nnumber];
 if( ! CheckCaptureIndex(index, pContext) )
 {
  return 0;
 }

 if( ! m_bright )
 {
  if(pContext->m_capturestack[index + 3] < 0)
  {
   pContext->m_capturestack[index + 3] ++;
   return 0;
  }

  pContext->m_capturestack.Restore(pContext->m_capturestack.GetSize() - 4);

  // to find
  CheckCaptureIndex(index, pContext);

  // new index
  pContext->m_captureindex[m_nnumber] = index;
 }
 else
 {
  if( pContext->m_capturestack[index + 2] >= 0 )
  {
   pContext->m_capturestack[index + 2] = -1;
   pContext->m_capturestack[index + 3] =  0;
  }
  else
  {
   pContext->m_capturestack[index + 3] --;
  }
 }

 return 0;
}

//
// Deletage
//
template <class CHART> class CDelegateElxT : public ElxInterface 
{
public:
 int Match    (CContext * pContext) const;
 int MatchNext(CContext * pContext) const;

public:
 CDelegateElxT(int ndata = 0);

public:
 ElxInterface * m_pelx;
 int m_ndata; // +0 : recursive to
              // -3 : named recursive

 CBufferT <CHART> m_szNamed;
};

template <class CHART> CDelegateElxT <CHART> :: CDelegateElxT(int ndata)
{
 m_pelx  = 0;
 m_ndata = ndata;
}

template <class CHART> int CDelegateElxT <CHART> :: Match(CContext * pContext) const
{
 if(m_pelx != 0)
  return m_pelx->Match(pContext);
 else
  return 1;
}

template <class CHART> int CDelegateElxT <CHART> :: MatchNext(CContext * pContext) const
{
 if(m_pelx != 0)
  return m_pelx->MatchNext(pContext);
 else
  return 0;
}

//
// Empty
//
template <int x> class CEmptyElxT : public ElxInterface
{
public:
 int Match    (CContext * pContext) const;
 int MatchNext(CContext * pContext) const;

public:
 CEmptyElxT();
};

typedef CEmptyElxT <0> CEmptyElx;

//
// Global
//
template <int x> class CGlobalElxT : public ElxInterface
{
public:
 int Match    (CContext * pContext) const;
 int MatchNext(CContext * pContext) const;

public:
 CGlobalElxT();
};

typedef CGlobalElxT <0> CGlobalElx;

//
// Repeat
//
template <int x> class CRepeatElxT : public ElxInterface
{
public:
 int Match    (CContext * pContext) const;
 int MatchNext(CContext * pContext) const;

public:
 CRepeatElxT(ElxInterface * pelx, int ntimes);

protected:
 int MatchFixed    (CContext * pContext) const;
 int MatchNextFixed(CContext * pContext) const;

public:
 ElxInterface * m_pelx;
 int m_nfixed;
};

typedef CRepeatElxT <0> CRepeatElx;

//
// Greedy
//
template <int x> class CGreedyElxT : public CRepeatElxT <x>
{
public:
 int Match    (CContext * pContext) const;
 int MatchNext(CContext * pContext) const;

public:
 CGreedyElxT(ElxInterface * pelx, int nmin = 0, int nmax = INT_MAX);

protected:
 int MatchVart    (CContext * pContext) const;
 int MatchNextVart(CContext * pContext) const;

public:
 int m_nvart;
};

typedef CGreedyElxT <0> CGreedyElx;

//
// Independent
//
template <int x> class CIndependentElxT : public ElxInterface
{
public:
 int Match    (CContext * pContext) const;
 int MatchNext(CContext * pContext) const;

public:
 CIndependentElxT(ElxInterface * pelx);

public:
 ElxInterface * m_pelx;
};

typedef CIndependentElxT <0> CIndependentElx;

//
// List
//
template <int x> class CListElxT : public ElxInterface
{
public:
 int Match    (CContext * pContext) const;
 int MatchNext(CContext * pContext) const;

public:
 CListElxT(int brightleft);

public:
 CBufferT <ElxInterface *> m_elxlist;
 int m_brightleft;
};

typedef CListElxT <0> CListElx;

//
// Posix Elx
//
template <class CHART> class CPosixElxT : public ElxInterface
{
public:
 int Match    (CContext * pContext) const;
 int MatchNext(CContext * pContext) const;

public:
 CPosixElxT(const char * posix, int brightleft);

public:
 POSIX_FUNC m_posixfun;
 int m_brightleft;
 int m_byes;
};

//
// Implementation
//
template <class CHART> CPosixElxT <CHART> :: CPosixElxT(const char * posix, int brightleft)
{
 m_brightleft = brightleft;

 if(posix[1] == '^')
 {
  m_byes = 0;
  posix += 2;
 }
 else
 {
  m_byes = 1;
  posix += 1;
 }

 if     (!strncmp(posix, "alnum:", 6)) m_posixfun = ::isalnum ;
 else if(!strncmp(posix, "alpha:", 6)) m_posixfun = ::isalpha ;
 else if(!strncmp(posix, "ascii:", 6)) m_posixfun = ::isascii ;
 else if(!strncmp(posix, "cntrl:", 6)) m_posixfun = ::iscntrl ;
 else if(!strncmp(posix, "digit:", 6)) m_posixfun = ::isdigit ;
 else if(!strncmp(posix, "graph:", 6)) m_posixfun = ::isgraph ;
 else if(!strncmp(posix, "lower:", 6)) m_posixfun = ::islower ;
 else if(!strncmp(posix, "print:", 6)) m_posixfun = ::isprint ;
 else if(!strncmp(posix, "punct:", 6)) m_posixfun = ::ispunct ;
 else if(!strncmp(posix, "space:", 6)) m_posixfun = ::isspace ;
 else if(!strncmp(posix, "upper:", 6)) m_posixfun = ::isupper ;
 else if(!strncmp(posix, "xdigit:",7)) m_posixfun = ::isxdigit;
 else if(!strncmp(posix, "blank:", 6)) m_posixfun =   isblank ;
 else                                  m_posixfun = 0         ;
}

inline int isblank(int c)
{
 return c == 0x20 || c == '/t';
}

template <class CHART> int CPosixElxT <CHART> :: Match(CContext * pContext) const
{
 if(m_posixfun == 0) return 0;

 int tlen = pContext->m_pMatchStringLength;
 int npos = pContext->m_nCurrentPos;

 // check
 int at   = m_brightleft ? npos - 1 : npos;
 if( at < 0 || at >= tlen )
  return 0;

 CHART ch = ((const CHART *)pContext->m_pMatchString)[at];

 int bsucc = (*m_posixfun)(ch);

 if( ! m_byes )
  bsucc = ! bsucc;

 if( bsucc )
  pContext->m_nCurrentPos += m_brightleft ? -1 : 1;

 return bsucc;
}

template <class CHART> int CPosixElxT <CHART> :: MatchNext(CContext * pContext) const
{
 pContext->m_nCurrentPos -= m_brightleft ? -1 : 1;
 return 0;
}

//
// Possessive
//
template <int x> class CPossessiveElxT : public CGreedyElxT <x>
{
public:
 int Match    (CContext * pContext) const;
 int MatchNext(CContext * pContext) const;

public:
 CPossessiveElxT(ElxInterface * pelx, int nmin = 0, int nmax = INT_MAX);
};

typedef CPossessiveElxT <0> CPossessiveElx;

//
// Range Elx
//
template <class CHART> class CRangeElxT : public ElxInterface
{
public:
 int Match    (CContext * pContext) const;
 int MatchNext(CContext * pContext) const;

public:
 CRangeElxT(int brightleft, int byes);

public:
 int IsContainChar(CHART ch) const;

public:
 CBufferT <CHART> m_ranges;
 CBufferT <CHART> m_chars;
 CBufferT <ElxInterface *> m_embeds;

public:
 int m_brightleft;
 int m_byes;
};

//
// Implementation
//
template <class CHART> CRangeElxT <CHART> :: CRangeElxT(int brightleft, int byes)
{
 m_brightleft = brightleft;
 m_byes       = byes;
}

template <class CHART> int CRangeElxT <CHART> :: Match(CContext * pContext) const
{
 int tlen = pContext->m_pMatchStringLength;
 int npos = pContext->m_nCurrentPos;

 // check
 int at   = m_brightleft ? npos - 1 : npos;
 if( at < 0 || at >= tlen )
  return 0;

 CHART ch = ((const CHART *)pContext->m_pMatchString)[at];
 int bsucc = 0, i;

 // compare
 for(i=0; !bsucc && i<m_ranges.GetSize(); i+=2)
 {
  if(m_ranges[i] <= ch && ch <= m_ranges[i+1]) bsucc = 1;
 }

 for(i=0; !bsucc && i<m_chars.GetSize(); i++)
 {
  if(m_chars[i] == ch) bsucc = 1;
 }

 for(i=0; !bsucc && i<m_embeds.GetSize(); i++)
 {
  if(m_embeds[i]->Match(pContext))
  {
   pContext->m_nCurrentPos = npos;
   bsucc = 1;
  }
 }

 if( ! m_byes )
  bsucc = ! bsucc;

 if( bsucc )
  pContext->m_nCurrentPos += m_brightleft ? -1 : 1;

 return bsucc;
}

template <class CHART> int CRangeElxT <CHART> :: IsContainChar(CHART ch) const
{
 int bsucc = 0, i;

 // compare
 for(i=0; !bsucc && i<m_ranges.GetSize(); i+=2)
 {
  if(m_ranges[i] <= ch && ch <= m_ranges[i+1]) bsucc = 1;
 }

 for(i=0; !bsucc && i<m_chars.GetSize(); i++)
 {
  if(m_chars[i] == ch) bsucc = 1;
 }

 return bsucc;
}

template <class CHART> int CRangeElxT <CHART> :: MatchNext(CContext * pContext) const
{
 pContext->m_nCurrentPos -= m_brightleft ? -1 : 1;
 return 0;
}

//
// Reluctant
//
template <int x> class CReluctantElxT : public CRepeatElxT <x>
{
public:
 int Match    (CContext * pContext) const;
 int MatchNext(CContext * pContext) const;

public:
 CReluctantElxT(ElxInterface * pelx, int nmin = 0, int nmax = INT_MAX);

protected:
 int MatchVart    (CContext * pContext) const;
 int MatchNextVart(CContext * pContext) const;

public:
 int m_nvart;
};

typedef CReluctantElxT <0> CReluctantElx;

//
// String Elx
//
template <class CHART> class CStringElxT : public ElxInterface
{
public:
 int Match    (CContext * pContext) const;
 int MatchNext(CContext * pContext) const;

public:
 CStringElxT(const CHART * fixed, int nlength, int brightleft, int bignorecase);

public:
 CBufferT <CHART> m_szPattern;
 int m_brightleft;
 int m_bignorecase;
};

//
// Implementation
//
template <class CHART> CStringElxT <CHART> :: CStringElxT(const CHART * fixed, int nlength, int brightleft, int bignorecase) : m_szPattern(fixed, nlength)
{
 m_brightleft  = brightleft;
 m_bignorecase = bignorecase;
}

template <class CHART> int CStringElxT <CHART> :: Match(CContext * pContext) const
{
 const CHART * pcsz  = (const CHART *)pContext->m_pMatchString;
 int npos = pContext->m_nCurrentPos;
 int tlen = pContext->m_pMatchStringLength;
 int slen = m_szPattern.GetSize();

 int bsucc;

 if(m_brightleft)
 {
  if(npos < slen)
   return 0;

  if(m_bignorecase)
   bsucc = ! m_szPattern.nCompareNoCase(pcsz + (npos - slen));
  else
   bsucc = ! m_szPattern.nCompare      (pcsz + (npos - slen));

  if( bsucc )
   pContext->m_nCurrentPos -= slen;
 }
 else
 {
  if(npos + slen > tlen)
   return 0;

  if(m_bignorecase)
   bsucc = ! m_szPattern.nCompareNoCase(pcsz + npos);
  else
   bsucc = ! m_szPattern.nCompare      (pcsz + npos);

  if( bsucc )
   pContext->m_nCurrentPos += slen;
 }

 return bsucc;
}

template <class CHART> int CStringElxT <CHART> :: MatchNext(CContext * pContext) const
{
 int slen = m_szPattern.GetSize();

 if(m_brightleft)
  pContext->m_nCurrentPos += slen;
 else
  pContext->m_nCurrentPos -= slen;

 return 0;
}

//
// CConditionElx
//
template <class CHART> class CConditionElxT : public ElxInterface
{
public:
 int Match    (CContext * pContext) const;
 int MatchNext(CContext * pContext) const;

public:
 CConditionElxT();

public:
 // backref condition
 int m_nnumber;
 CBufferT <CHART> m_szNamed;

 // elx condition
 ElxInterface * m_pelxask;

 // selection
 ElxInterface * m_pelxyes, * m_pelxno;
};

template <class CHART> CConditionElxT <CHART> :: CConditionElxT()
{
 m_nnumber = -1;
}

template <class CHART> int CConditionElxT <CHART> :: Match(CContext * pContext) const
{
 // status
 int nbegin = pContext->m_nCurrentPos;
 int nsize  = pContext->m_stack.GetSize();
 int ncsize = pContext->m_capturestack.GetSize();

 // condition result
 int condition_yes = 0;

 // backref type
 if( m_nnumber >= 0 )
 {
  do
  {
   if(m_nnumber >= pContext->m_captureindex.GetSize()) break;

   int index = pContext->m_captureindex[m_nnumber];
   if( index < 0) break;

   // else valid
   condition_yes = 1;
  }
  while(0);
 }
 else
 {
  if( m_pelxask == 0 )
   condition_yes = 1;
  else
   condition_yes = m_pelxask->Match(pContext);

  pContext->m_stack.Restore(nsize);
  pContext->m_nCurrentPos = nbegin;
 }

 // elx result
 int bsucc;
 if( condition_yes )
  bsucc = m_pelxyes == 0 ? 1 : m_pelxyes->Match(pContext);
 else
  bsucc = m_pelxno  == 0 ? 1 : m_pelxno ->Match(pContext);

 if( bsucc )
 {
  pContext->m_stack.Push(ncsize);
  pContext->m_stack.Push(condition_yes);
 }
 else
 {
  pContext->m_capturestack.Restore(ncsize);
 }

 return bsucc;
}

template <class CHART> int CConditionElxT <CHART> :: MatchNext(CContext * pContext) const
{
 // pop
 int ncsize, condition_yes;

 pContext->m_stack.Pop(condition_yes);
 pContext->m_stack.Pop(ncsize);

 // elx result
 int bsucc;
 if( condition_yes )
  bsucc = m_pelxyes == 0 ? 0 : m_pelxyes->MatchNext(pContext);
 else
  bsucc = m_pelxno  == 0 ? 0 : m_pelxno ->MatchNext(pContext);

 if( bsucc )
 {
  pContext->m_stack.Push(ncsize);
  pContext->m_stack.Push(condition_yes);
 }
 else
 {
  pContext->m_capturestack.Restore(ncsize);
 }

 return bsucc;
}

//
// MatchResult
//
template <int x> class MatchResultT
{
public:
 int IsMatched() const;

public:
 int GetStart() const;
 int GetEnd  () const;

public:
 int MaxGroupNumber() const;
 int GetGroupStart(int nGroupNumber) const;
 int GetGroupEnd  (int nGroupNumber) const;

public:
 MatchResultT(const MatchResultT <x> & from) { *this = from; }
 MatchResultT(CContext * pContext = 0, int nMaxNumber = -1);
 MatchResultT <x> & operator = (const MatchResultT <x> &);
 inline operator int() const { return IsMatched(); }

public:
 CBufferT <int> m_result;
};

typedef MatchResultT <0> MatchResult;

// Stocked Elx IDs
enum STOCKELX_ID_DEFINES
{
 STOCKELX_EMPTY = 0,

 ///

 STOCKELX_DOT_ALL,
 STOCKELX_DOT_NOT_ALL,

 STOCKELX_WORD,
 STOCKELX_WORD_NOT,

 STOCKELX_SPACE,
 STOCKELX_SPACE_NOT,

 STOCKELX_DIGITAL,
 STOCKELX_DIGITAL_NOT,

 //

 STOCKELX_DOT_ALL_RIGHTLEFT,
 STOCKELX_DOT_NOT_ALL_RIGHTLEFT,

 STOCKELX_WORD_RIGHTLEFT,
 STOCKELX_WORD_RIGHTLEFT_NOT,

 STOCKELX_SPACE_RIGHTLEFT,
 STOCKELX_SPACE_RIGHTLEFT_NOT,

 STOCKELX_DIGITAL_RIGHTLEFT,
 STOCKELX_DIGITAL_RIGHTLEFT_NOT,

 /

 STOCKELX_COUNT
};

// REGEX_FLAGS
#ifndef _REGEX_FLAGS_DEFINED
 enum REGEX_FLAGS
 {
  NO_FLAG        = 0,
  SINGLELINE     = 0x01,
  MULTILINE      = 0x02,
  GLOBAL         = 0x04,
  IGNORECASE     = 0x08,
  RIGHTTOLEFT    = 0x10,
  EXTENDED       = 0x20
 };
 #define _REGEX_FLAGS_DEFINED
#endif

//
// Builder T
//
template <class CHART> class CBuilderT
{
public:
 typedef CDelegateElxT  <CHART> CDelegateElx;
 typedef CBracketElxT   <CHART> CBracketElx;
 typedef CBackrefElxT   <CHART> CBackrefElx;
 typedef CConditionElxT <CHART> CConditionElx;

// Methods
public:
 ElxInterface * Build(const CBufferRefT <CHART> & pattern, int flags);
 int GetNamedNumber(const CBufferRefT <CHART> & named) const;
 void Clear();

public:
  CBuilderT();
 ~CBuilderT();

// Public Attributes
public:
 ElxInterface * m_pTopElx;
 int            m_nFlags;
 int            m_nMaxNumber;
 int            m_nNextNamed;
 int            m_nGroupCount;

 CBufferT <ElxInterface  *> m_objlist;
 CBufferT <ElxInterface  *> m_grouplist;
 CBufferT <CDelegateElx  *> m_recursivelist;
 CBufferT <CListElx      *> m_namedlist;
 CBufferT <CBackrefElx   *> m_namedbackreflist;
 CBufferT <CConditionElx *> m_namedconditionlist;

// CHART_INFO
protected:
 struct CHART_INFO
 {
 public:
  CHART ch;
  int   type;
  int   pos;
  int   len;

 public:
  CHART_INFO(CHART c, int t, int p = 0, int l = 0) { ch = c; type = t; pos = p; len = l;    }
  inline int operator == (const CHART_INFO & ci)   { return ch == ci.ch && type == ci.type; }
  inline int operator != (const CHART_INFO & ci)   { return ! operator == (ci);             }
 };

protected:
 static unsigned int Hex2Int(const CHART * pcsz, int length, int & used);
 static int ReadDec(char * & str, unsigned int & dec);
 void MoveNext();
 int  GetNext2();

 ElxInterface * BuildAlternative(int vaflags);
 ElxInterface * BuildList       (int & flags);
 ElxInterface * BuildRepeat     (int & flags);
 ElxInterface * BuildSimple     (int & flags);
 ElxInterface * BuildCharset    (int & flags);
 ElxInterface * BuildRecursive  (int & flags);
 ElxInterface * BuildBoundary   (int & flags);
 ElxInterface * BuildBackref    (int & flags);

 ElxInterface * GetStockElx     (int nStockId);
 ElxInterface * Keep(ElxInterface * pElx);

// Private Attributes
protected:
 CBufferRefT <CHART> m_pattern;
 CHART_INFO prev, curr, next, nex2;
 int m_nNextPos;
 int m_nCharsetDepth;
 int m_bQuoted;
 POSIX_FUNC m_quote_fun;

 ElxInterface * m_pStockElxs[STOCKELX_COUNT];
};

//
// Implementation
//
template <class CHART> CBuilderT <CHART> :: CBuilderT() : m_pattern(0, 0), prev(0, 0), curr(0, 0), next(0, 0), nex2(0, 0)
{
 Clear();
}

template <class CHART> CBuilderT <CHART> :: ~CBuilderT()
{
 Clear();
}

template <class CHART> int CBuilderT <CHART> :: GetNamedNumber(const CBufferRefT <CHART> & named) const
{
 for(int i=0; i<m_namedlist.GetSize(); i++)
 {
  if( ! ((CBracketElx *)m_namedlist[i]->m_elxlist[0])->m_szNamed.CompareNoCase(named) )
   return ((CBracketElx *)m_namedlist[i]->m_elxlist[0])->m_nnumber;
 }

 return -3;
}

template <class CHART> ElxInterface * CBuilderT <CHART> :: Build(const CBufferRefT <CHART> & pattern, int flags)
{
 // init
 m_pattern       = pattern;
 m_nNextPos      = 0;
 m_nCharsetDepth = 0;
 m_nMaxNumber    = 0;
 m_nNextNamed    = 0;
 m_nFlags        = flags;
 m_bQuoted       = 0;
 m_quote_fun     = 0;

 m_grouplist         .Restore(0);
 m_recursivelist     .Restore(0);
 m_namedlist         .Restore(0);
 m_namedbackreflist  .Restore(0);
 m_namedconditionlist.Restore(0);

 int i;
 for(i=0; i<3; i++) MoveNext();

 // build
 m_pTopElx = BuildAlternative(flags);

 // group 0
 m_grouplist.Prepare(0);
 m_grouplist[0] = m_pTopElx;

 // append named to unnamed
 m_nGroupCount = m_grouplist.GetSize();

 m_grouplist.Prepare(m_nMaxNumber + m_namedlist.GetSize());

 for(i=0; i<m_namedlist.GetSize(); i++)
 {
  CBracketElx * pleft  = (CBracketElx *)m_namedlist[i]->m_elxlist[0];
  CBracketElx * pright = (CBracketElx *)m_namedlist[i]->m_elxlist[2];

  // append
  m_grouplist[m_nGroupCount ++] = m_namedlist[i];

  if( pleft->m_nnumber > 0 )
   continue;

  // same name
  int find_same_name = GetNamedNumber(pleft->m_szNamed);
  if( find_same_name >= 0 )
  {
   pleft ->m_nnumber = find_same_name;
   pright->m_nnumber = find_same_name;
  }
  else
  {
   m_nMaxNumber ++;

   pleft ->m_nnumber = m_nMaxNumber;
   pright->m_nnumber = m_nMaxNumber;
  }
 }

 for(i=1; i<m_nGroupCount; i++)
 {
  CBracketElx * pleft = (CBracketElx *)((CListElx*)m_grouplist[i])->m_elxlist[0];

  if( pleft->m_nnumber > m_nMaxNumber )
   m_nMaxNumber = pleft->m_nnumber;
 }

 // connect recursive
 for(i=0; i<m_recursivelist.GetSize(); i++)
 {
  if( m_recursivelist[i]->m_ndata == -3 )
   m_recursivelist[i]->m_ndata = GetNamedNumber(m_recursivelist[i]->m_szNamed);

  if( m_recursivelist[i]->m_ndata >= 0 && m_recursivelist[i]->m_ndata <= m_nMaxNumber )
  {
   if( m_recursivelist[i]->m_ndata == 0 )
    m_recursivelist[i]->m_pelx = m_pTopElx;
   else for(int j=1; j<m_grouplist.GetSize(); j++)
   {
    if(m_recursivelist[i]->m_ndata == ((CBracketElx *)((CListElx*)m_grouplist[j])->m_elxlist[0])->m_nnumber)
    {
     m_recursivelist[i]->m_pelx = m_grouplist[j];
     break;
    }
   }
  }
 }

 // named backref
 for(i=0; i<m_namedbackreflist.GetSize(); i++)
 {
  m_namedbackreflist[i]->m_nnumber = GetNamedNumber(m_namedbackreflist[i]->m_szNamed);
 }

 // named condition
 for(i=0; i<m_namedconditionlist.GetSize(); i++)
 {
  int nn = GetNamedNumber(m_namedconditionlist[i]->m_szNamed);
  if( nn >= 0 )
  {
   m_namedconditionlist[i]->m_nnumber = nn;
   m_namedconditionlist[i]->m_pelxask = 0;
  }
 }

 return m_pTopElx;
}

template <class CHART> void CBuilderT <CHART> :: Clear()
{
 for(int i=0; i<m_objlist.GetSize(); i++)
 {
  delete m_objlist[i];
 }

 m_objlist.Restore(0);
 m_pTopElx = 0;
 m_nMaxNumber = 0;

 memset(m_pStockElxs, 0, sizeof(m_pStockElxs));
}

//
// hex to int
//
template <class CHART> unsigned int CBuilderT <CHART> :: Hex2Int(const CHART * pcsz, int length, int & used)
{
 unsigned int result = 0;
 int & i = used;

 for(i=0; i<length; i++)
 {
  if(pcsz[i] >= RCHART('0') && pcsz[i] <= RCHART('9'))
   result = (result << 4) + (pcsz[i] - RCHART('0'));
  else if(pcsz[i] >= RCHART('A') && pcsz[i] <= RCHART('F'))
   result = (result << 4) + (0x0A + (pcsz[i] - RCHART('A')));
  else if(pcsz[i] >= RCHART('a') && pcsz[i] <= RCHART('f'))
   result = (result << 4) + (0x0A + (pcsz[i] - RCHART('a')));
  else
   break;
 }

 return result;
}

template <class CHART> inline ElxInterface * CBuilderT <CHART> :: Keep(ElxInterface * pelx)
{
 m_objlist.Push(pelx);
 return pelx;
}

template <class CHART> void CBuilderT <CHART> :: MoveNext()
{
 // forwards
 prev = curr;
 curr = next;
 next = nex2;

 // get nex2
 while( ! GetNext2() ) {};
}

template <class CHART> int CBuilderT <CHART> :: GetNext2()
{
 // check length
 if(m_nNextPos >= m_pattern.GetSize())
 {
  nex2 = CHART_INFO(0, 1, m_nNextPos, 0);
  return 1;
 }

 int   delta = 1;
 CHART ch    = m_pattern[m_nNextPos];

 // if quoted
 if(m_bQuoted)
 {
  if(ch == RCHART('//'))
  {
   if(m_pattern[m_nNextPos + 1] == RCHART('E'))
   {
    m_quote_fun = 0;
    m_bQuoted   = 0;
    m_nNextPos += 2;
    return 0;
   }
  }

  if(m_quote_fun != 0)
   nex2 = CHART_INFO((CHART)(*m_quote_fun)((int)ch), 0, m_nNextPos, delta);
  else
   nex2 = CHART_INFO(ch, 0, m_nNextPos, delta);

  m_nNextPos += delta;

  return 1;
 }

 // common
 switch(ch)
 {
 case RCHART('//'):
  {
   CHART ch1 = m_pattern[m_nNextPos+1];

   // backref
   if(ch1 >= RCHART('0') && ch1 <= RCHART('9'))
   {
    nex2 = CHART_INFO(ch, 1, m_nNextPos, delta);
    break;
   }

   // escape
   delta     = 2;

   switch(ch1)
   {
   case RCHART('A'):
   case RCHART('Z'):
   case RCHART('z'):
   case RCHART('w'):
   case RCHART('W'):
   case RCHART('s'):
   case RCHART('S'):
   case RCHART('B'):
   case RCHART('d'):
   case RCHART('D'):
   case RCHART('k'):
   case RCHART('g'):
    nex2 = CHART_INFO(ch1, 1, m_nNextPos, delta);
    break;

   case RCHART('b'):
    if(m_nCharsetDepth > 0)
     nex2 = CHART_INFO('/b', 0, m_nNextPos, delta);
    else
     nex2 = CHART_INFO(ch1, 1, m_nNextPos, delta);
    break;

   /*
   case RCHART('<'):
   case RCHART('>'):
    if(m_nCharsetDepth > 0)
     nex2 = CHART_INFO(ch1, 0, m_nNextPos, delta);
    else
     nex2 = CHART_INFO(ch1, 1, m_nNextPos, delta);
    break;
   */

   case RCHART('x'):
    if(m_pattern[m_nNextPos+2] != '{')
    {
     int red = 0;
     unsigned int ch2 = Hex2Int(m_pattern.GetBuffer() + m_nNextPos + 2, 2, red);

     delta += red;

     if(red > 0)
      nex2 = CHART_INFO(RCHART(ch2), 0, m_nNextPos, delta);
     else
      nex2 = CHART_INFO(ch1, 0, m_nNextPos, delta);

     break;
    }

   case RCHART('u'):
    if(m_pattern[m_nNextPos+2] != '{')
    {
     int red = 0;
     unsigned int ch2 = Hex2Int(m_pattern.GetBuffer() + m_nNextPos + 2, 4, red);

     delta += red;

     if(red > 0)
      nex2 = CHART_INFO(RCHART(ch2), 0, m_nNextPos, delta);
     else
      nex2 = CHART_INFO(ch1, 0, m_nNextPos, delta);
    }
    else
    {
     int red = 0;
     unsigned int ch2 = Hex2Int(m_pattern.GetBuffer() + m_nNextPos + 3, sizeof(int) * 2, red);

     delta += red;

     while(m_nNextPos + delta < m_pattern.GetSize() && m_pattern.At(m_nNextPos + delta) != RCHART('}'))
      delta ++;

     delta ++; // skip '}'

     nex2 = CHART_INFO(RCHART(ch2), 0, m_nNextPos, delta);
    }
    break;

   case RCHART('a'): nex2 = CHART_INFO(RCHART('/a'), 0, m_nNextPos, delta); break;
   case RCHART('f'): nex2 = CHART_INFO(RCHART('/f'), 0, m_nNextPos, delta); break;
   case RCHART('n'): nex2 = CHART_INFO(RCHART('/n'), 0, m_nNextPos, delta); break;
   case RCHART('r'): nex2 = CHART_INFO(RCHART('/r'), 0, m_nNextPos, delta); break;
   case RCHART('t'): nex2 = CHART_INFO(RCHART('/t'), 0, m_nNextPos, delta); break;
   case RCHART('v'): nex2 = CHART_INFO(RCHART('/v'), 0, m_nNextPos, delta); break;
   case RCHART('e'): nex2 = CHART_INFO(RCHART( 27 ), 0, m_nNextPos, delta); break;

   case RCHART('G'):  // skip '/G'
    if(m_nCharsetDepth > 0)
    {
     m_nNextPos += 2;
     return 0;
    }
    else
    {
     nex2 = CHART_INFO(ch1, 1, m_nNextPos, delta);
     break;
    }

   case RCHART('L'):
    if( ! m_quote_fun ) m_quote_fun = ::tolower;

   case RCHART('U'):
    if( ! m_quote_fun ) m_quote_fun = ::toupper;

   case RCHART('Q'):
    {
     m_bQuoted   = 1;
     m_nNextPos += 2;
     return 0;
    }

   case RCHART('E'):
    {
     m_quote_fun = 0;
     m_bQuoted   = 0;
     m_nNextPos += 2;
     return 0;
    }

   case 0:
    if(m_nNextPos+1 >= m_pattern.GetSize())
    {
     delta = 1;
     nex2 = CHART_INFO(ch , 0, m_nNextPos, delta);
    }
    else
     nex2 = CHART_INFO(ch1, 0, m_nNextPos, delta); // common '/0' char
    break;

   default:
    nex2 = CHART_INFO(ch1, 0, m_nNextPos, delta);
    break;
   }
  }
  break;

 case RCHART('*'):
 case RCHART('+'):
 case RCHART('?'):
 case RCHART('.'):
 case RCHART('{'):
 case RCHART('}'):
 case RCHART(')'):
 case RCHART('|'):
 case RCHART('$'):
  if(m_nCharsetDepth > 0)
   nex2 = CHART_INFO(ch, 0, m_nNextPos, delta);
  else
   nex2 = CHART_INFO(ch, 1, m_nNextPos, delta);
  break;

 case RCHART('-'):
  if(m_nCharsetDepth > 0)
   nex2 = CHART_INFO(ch, 1, m_nNextPos, delta);
  else
   nex2 = CHART_INFO(ch, 0, m_nNextPos, delta);
  break;

 case RCHART('('):
  {
   CHART ch1 = m_pattern[m_nNextPos+1];
   CHART ch2 = m_pattern[m_nNextPos+2];

   // skip remark
   if(ch1 == RCHART('?') && ch2 == RCHART('#'))
   {
    m_nNextPos += 2;
    while(m_nNextPos < m_pattern.GetSize())
    {
     if(m_pattern[m_nNextPos] == RCHART(')'))
      break;

     m_nNextPos ++;
    }

    if(m_pattern[m_nNextPos] == RCHART(')'))
    {
     m_nNextPos ++;

     // get next nex2
     return 0;
    }
   }
   else
   {
    if(m_nCharsetDepth > 0)
     nex2 = CHART_INFO(ch, 0, m_nNextPos, delta);
    else
     nex2 = CHART_INFO(ch, 1, m_nNextPos, delta);
   }
  }
  break;

 case RCHART('#'):
  if(m_nFlags & EXTENDED)
  {
   // skip remark
   m_nNextPos ++;

   while(m_nNextPos < m_pattern.GetSize())
   {
    if(m_pattern[m_nNextPos] == RCHART('/n') || m_pattern[m_nNextPos] == RCHART('/r'))
     break;

    m_nNextPos ++;
   }

   // get next nex2
   return 0;
  }
  else
  {
   nex2 = CHART_INFO(ch, 0, m_nNextPos, delta);
  }
  break;

 case RCHART(' '):
 case RCHART('/f'):
 case RCHART('/n'):
 case RCHART('/r'):
 case RCHART('/t'):
 case RCHART('/v'):
  if(m_nFlags & EXTENDED)
  {
   m_nNextPos ++;

   // get next nex2
   return 0;
  }
  else
  {
   nex2 = CHART_INFO(ch, 0, m_nNextPos, delta);
  }
  break;

 case RCHART('['):
  if( m_nCharsetDepth == 0 || m_pattern.At(m_nNextPos + 1, 0) == RCHART(':') )
  {
   m_nCharsetDepth ++;
   nex2 = CHART_INFO(ch, 1, m_nNextPos, delta);
  }
  else
  {
   nex2 = CHART_INFO(ch, 0, m_nNextPos, delta);
  }
  break;

 case RCHART(']'):
  if(m_nCharsetDepth > 0)
  {
   m_nCharsetDepth --;
   nex2 = CHART_INFO(ch, 1, m_nNextPos, delta);
  }
  else
  {
   nex2 = CHART_INFO(ch, 0, m_nNextPos, delta);
  }
  break;

 case RCHART(':'):
  if(next == CHART_INFO(RCHART('['), 1))
   nex2 = CHART_INFO(ch, 1, m_nNextPos, delta);
  else
   nex2 = CHART_INFO(ch, 0, m_nNextPos, delta);
  break;

 case RCHART('^'):
  if(m_nCharsetDepth == 0 || next == CHART_INFO(RCHART('['), 1) || (curr == CHART_INFO(RCHART('['), 1) && next == CHART_INFO(RCHART(':'), 1)))
   nex2 = CHART_INFO(ch, 1, m_nNextPos, delta);
  else
   nex2 = CHART_INFO(ch, 0, m_nNextPos, delta);
  break;

 case 0:
  if(m_nNextPos >= m_pattern.GetSize())
   nex2 = CHART_INFO(ch, 1, m_nNextPos, delta); // end of string
  else
   nex2 = CHART_INFO(ch, 0, m_nNextPos, delta); // common '/0' char
  break;

 default:
  nex2 = CHART_INFO(ch, 0, m_nNextPos, delta);
  break;
 }

 m_nNextPos += delta;

 return 1;
}

template <class CHART> ElxInterface * CBuilderT <CHART> :: GetStockElx(int nStockId)
{
 ElxInterface ** pStockElxs = m_pStockElxs;

 // check
 if(nStockId < 0 || nStockId >= STOCKELX_COUNT)
  return GetStockElx(0);

 // create if no
 if(pStockElxs[nStockId] == 0)
 {
  switch(nStockId)
  {
  case STOCKELX_EMPTY:
   pStockElxs[nStockId] = Keep(new CEmptyElx());
   break;

  case STOCKELX_WORD:
   {
    CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART> (0, 1));

    pRange->m_ranges.Push(RCHART('A')); pRange->m_ranges.Push(RCHART('Z'));
    pRange->m_ranges.Push(RCHART('a')); pRange->m_ranges.Push(RCHART('z'));
    pRange->m_ranges.Push(RCHART('0')); pRange->m_ranges.Push(RCHART('9'));
    pRange->m_chars .Push(RCHART('_'));

    pStockElxs[nStockId] = pRange;
   }
   break;

  case STOCKELX_WORD_NOT:
   {
    CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART> (0, 0));

    pRange->m_ranges.Push(RCHART('A')); pRange->m_ranges.Push(RCHART('Z'));
    pRange->m_ranges.Push(RCHART('a')); pRange->m_ranges.Push(RCHART('z'));
    pRange->m_ranges.Push(RCHART('0')); pRange->m_ranges.Push(RCHART('9'));
    pRange->m_chars .Push(RCHART('_'));

    pStockElxs[nStockId] = pRange;
   }
   break;

  case STOCKELX_DOT_ALL:
   pStockElxs[nStockId] = Keep(new CRangeElxT <CHART> (0, 0));
   break;

  case STOCKELX_DOT_NOT_ALL:
   {
    CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART> (0, 0));

    pRange->m_chars .Push(RCHART('/n'));

    pStockElxs[nStockId] = pRange;
   }
   break;

  case STOCKELX_SPACE:
   {
    CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART> (0, 1));

    pRange->m_chars .Push(RCHART(' '));
    pRange->m_chars .Push(RCHART('/t'));
    pRange->m_chars .Push(RCHART('/r'));
    pRange->m_chars .Push(RCHART('/n'));

    pStockElxs[nStockId] = pRange;
   }
   break;

  case STOCKELX_SPACE_NOT:
   {
    CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART> (0, 0));

    pRange->m_chars .Push(RCHART(' '));
    pRange->m_chars .Push(RCHART('/t'));
    pRange->m_chars .Push(RCHART('/r'));
    pRange->m_chars .Push(RCHART('/n'));

    pStockElxs[nStockId] = pRange;
   }
   break;

  case STOCKELX_DIGITAL:
   {
    CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART> (0, 1));

    pRange->m_ranges.Push(RCHART('0')); pRange->m_ranges.Push(RCHART('9'));

    pStockElxs[nStockId] = pRange;
   }
   break;

  case STOCKELX_DIGITAL_NOT:
   {
    CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART> (0, 0));

    pRange->m_ranges.Push(RCHART('0')); pRange->m_ranges.Push(RCHART('9'));

    pStockElxs[nStockId] = pRange;
   }
   break;

  case STOCKELX_WORD_RIGHTLEFT:
   {
    CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART> (1, 1));

    pRange->m_ranges.Push(RCHART('A')); pRange->m_ranges.Push(RCHART('Z'));
    pRange->m_ranges.Push(RCHART('a')); pRange->m_ranges.Push(RCHART('z'));
    pRange->m_ranges.Push(RCHART('0')); pRange->m_ranges.Push(RCHART('9'));
    pRange->m_chars .Push(RCHART('_'));

    pStockElxs[nStockId] = pRange;
   }
   break;

  case STOCKELX_WORD_RIGHTLEFT_NOT:
   {
    CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART> (1, 0));

    pRange->m_ranges.Push(RCHART('A')); pRange->m_ranges.Push(RCHART('Z'));
    pRange->m_ranges.Push(RCHART('a')); pRange->m_ranges.Push(RCHART('z'));
    pRange->m_ranges.Push(RCHART('0')); pRange->m_ranges.Push(RCHART('9'));
    pRange->m_chars .Push(RCHART('_'));

    pStockElxs[nStockId] = pRange;
   }
   break;

  case STOCKELX_DOT_ALL_RIGHTLEFT:
   pStockElxs[nStockId] = Keep(new CRangeElxT <CHART> (1, 0));
   break;

  case STOCKELX_DOT_NOT_ALL_RIGHTLEFT:
   {
    CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART> (1, 0));

    pRange->m_chars .Push(RCHART('/n'));

    pStockElxs[nStockId] = pRange;
   }
   break;

  case STOCKELX_SPACE_RIGHTLEFT:
   {
    CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART> (1, 1));

    pRange->m_chars .Push(RCHART(' '));
    pRange->m_chars .Push(RCHART('/t'));
    pRange->m_chars .Push(RCHART('/r'));
    pRange->m_chars .Push(RCHART('/n'));
    pRange->m_chars .Push(RCHART('/f'));
    pRange->m_chars .Push(RCHART('/v'));

    pStockElxs[nStockId] = pRange;
   }
   break;

  case STOCKELX_SPACE_RIGHTLEFT_NOT:
   {
    CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART> (1, 0));

    pRange->m_chars .Push(RCHART(' '));
    pRange->m_chars .Push(RCHART('/t'));
    pRange->m_chars .Push(RCHART('/r'));
    pRange->m_chars .Push(RCHART('/n'));
    pRange->m_chars .Push(RCHART('/f'));
    pRange->m_chars .Push(RCHART('/v'));

    pStockElxs[nStockId] = pRange;
   }
   break;

  case STOCKELX_DIGITAL_RIGHTLEFT:
   {
    CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART> (1, 1));

    pRange->m_ranges.Push(RCHART('0')); pRange->m_ranges.Push(RCHART('9'));

    pStockElxs[nStockId] = pRange;
   }
   break;

  case STOCKELX_DIGITAL_RIGHTLEFT_NOT:
   {
    CRangeElxT <CHART> * pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART> (1, 0));

    pRange->m_ranges.Push(RCHART('0')); pRange->m_ranges.Push(RCHART('9'));

    pStockElxs[nStockId] = pRange;
   }
   break;
  }
 }

 // return
 return pStockElxs[nStockId];
}

template <class CHART> ElxInterface * CBuilderT <CHART> :: BuildAlternative(int vaflags)
{
 if(curr == CHART_INFO(0, 1))
  return GetStockElx(STOCKELX_EMPTY);

 // flag instance
 int flags = vaflags;

 // first part
 ElxInterface * pAlternativeOne = BuildList(flags);

 // check alternative
 if(curr == CHART_INFO(RCHART('|'), 1))
 {
  CAlternativeElx * pAlternative = (CAlternativeElx *)Keep(new CAlternativeElx());
  pAlternative->m_elxlist.Push(pAlternativeOne);

  // loop
  while(curr == CHART_INFO(RCHART('|'), 1))
  {
   // skip '|' itself
   MoveNext();

   pAlternativeOne = BuildList(flags);
   pAlternative->m_elxlist.Push(pAlternativeOne);
  }

  return pAlternative;
 }

 return pAlternativeOne;
}

template <class CHART> ElxInterface * CBuilderT <CHART> :: BuildList(int & flags)
{
 if(curr == CHART_INFO(0, 1) || curr == CHART_INFO(RCHART('|'), 1) || curr == CHART_INFO(RCHART(')'), 1))
  return GetStockElx(STOCKELX_EMPTY);

 // first
 ElxInterface * pListOne = BuildRepeat(flags);

 if(curr != CHART_INFO(0, 1) && curr != CHART_INFO(RCHART('|'), 1) && curr != CHART_INFO(RCHART(')'), 1))
 {
  CListElx * pList = (CListElx *)Keep(new CListElx(flags & RIGHTTOLEFT));
  pList->m_elxlist.Push(pListOne);

  while(curr != CHART_INFO(0, 1) && curr != CHART_INFO(RCHART('|'), 1) && curr != CHART_INFO(RCHART(')'), 1))
  {
   pListOne = BuildRepeat(flags);

   // add
   pList->m_elxlist.Push(pListOne);
  }

  return pList;
 }

 return pListOne;
}

template <class CHART> ElxInterface * CBuilderT <CHART> :: BuildRepeat(int & flags)
{
 // simple
 ElxInterface * pSimple = BuildSimple(flags);

 if(curr.type == 0) return pSimple;

 // is quantifier or not
 int bIsQuantifier = 1;

 // quantifier range
 unsigned int nMin = 0, nMax = 0;

 switch(curr.ch)
 {
 case RCHART('{'):
  {
   CBufferT <char> re;

   // skip '{'
   MoveNext();

   // copy
   while(curr != CHART_INFO(0, 1) && curr != CHART_INFO(RCHART('}'), 1))
   {
    re.Append(((curr.ch & (CHART)0xff) == curr.ch) ? (char)curr.ch : 0, 1);
    MoveNext();
   }

   // skip '}'
   MoveNext();

   // read
   int red;
   char * str = re.GetBuffer();

   if( ! ReadDec(str, nMin) )
    red = 0;
   else if( *str != ',' )
    red = 1;
   else
   {
    str ++;

    if( ! ReadDec(str, nMax) )
     red = 2;
    else
     red = 3;
   }

   // check
   if(red  <=  1 ) nMax = nMin;
   if(red  ==  2 ) nMax = INT_MAX;
   if(nMax < nMin) nMax = nMin;
  }
  break;

 case RCHART('?'):
  nMin = 0;
  nMax = 1;

  // skip '?'
  MoveNext();
  break;

 case RCHART('*'):
  nMin = 0;
  nMax = INT_MAX;

  // skip '*'
  MoveNext();
  break;

 case RCHART('+'):
  nMin = 1;
  nMax = INT_MAX;

  // skip '+'
  MoveNext();
  break;

 default:
  bIsQuantifier = 0;
  break;
 }

 // do quantify
 if(bIsQuantifier)
 {
  // 0 times
  if(nMax == 0)
   return GetStockElx(STOCKELX_EMPTY);

  // fixed times
  if(nMin == nMax)
  {
   if(curr == CHART_INFO(RCHART('?'), 1) || curr == CHART_INFO(RCHART('+'), 1))
    MoveNext();

   return Keep(new CRepeatElx(pSimple, nMin));
  }

  // range times
  if(curr == CHART_INFO(RCHART('?'), 1))
  {
   MoveNext();
   return Keep(new CReluctantElx(pSimple, nMin, nMax));
  }
  else if(curr == CHART_INFO(RCHART('+'), 1))
  {
   MoveNext();
   return Keep(new CPossessiveElx(pSimple, nMin, nMax));
  }
  else
  {
   return Keep(new CGreedyElx(pSimple, nMin, nMax));
  }
 }

 return pSimple;
}

template <class CHART> ElxInterface * CBuilderT <CHART> :: BuildSimple(int & flags)
{
 CBufferT <CHART> fixed;

 while(curr != CHART_INFO(0, 1))
 {
  if(curr.type == 0)
  {
   if(next == CHART_INFO(RCHART('{'), 1) || next == CHART_INFO(RCHART('?'), 1) || next == CHART_INFO(RCHART('*'), 1) || next == CHART_INFO(RCHART('+'), 1))
   {
    if(fixed.GetSize() == 0)
    {
     fixed.Append(curr.ch, 1);
     MoveNext();
    }

    break;
   }
   else
   {
    fixed.Append(curr.ch, 1);
    MoveNext();
   }
  }
  else if(curr.type == 1)
  {
   CHART vch = curr.ch;

   // end of simple
   if(vch == RCHART(')') || vch == RCHART('|'))
    break;

   // has fixed already
   if(fixed.GetSize() > 0)
    break;

   // left parentheses
   if(vch == RCHART('('))
   {
    return BuildRecursive(flags);
   }

   // char set
   if( vch == RCHART('[') || vch == RCHART('.') || vch == RCHART('w') || vch == RCHART('W') ||
    vch == RCHART('s') || vch == RCHART('S') || vch == RCHART('d') || vch == RCHART('D')
   )
   {
    return BuildCharset(flags);
   }

   // boundary
   if( vch == RCHART('^') || vch == RCHART('$') || vch == RCHART('A') || vch == RCHART('Z') || vch == RCHART('z') ||
    vch == RCHART('b') || vch == RCHART('B') || vch == RCHART('G') // vch == RCHART('<') || vch == RCHART('>')
   )
   {
    return BuildBoundary(flags);
   }

   // backref
   if(vch == RCHART('//') || vch == RCHART('k') || vch == RCHART('g'))
   {
    return BuildBackref(flags);
   }

   // treat vchar as char
   fixed.Append(curr.ch, 1);
   MoveNext();
  }
 }

 if(fixed.GetSize() > 0)
  return Keep(new CStringElxT <CHART> (fixed.GetBuffer(), fixed.GetSize(), flags & RIGHTTOLEFT, flags & IGNORECASE));
 else
  return GetStockElx(STOCKELX_EMPTY);
}

#define max(a, b)  (((a) > (b)) ? (a) : (b))
#define min(a, b)  (((a) < (b)) ? (a) : (b))

template <class CHART> ElxInterface * CBuilderT <CHART> :: BuildCharset(int & flags)
{
 // char
 CHART ch = curr.ch;

 // skip
 MoveNext();

 switch(ch)
 {
 case RCHART('.'):
  return GetStockElx(
   flags & RIGHTTOLEFT ?
   ((flags & SINGLELINE) ? STOCKELX_DOT_ALL_RIGHTLEFT : STOCKELX_DOT_NOT_ALL_RIGHTLEFT) :
   ((flags & SINGLELINE) ? STOCKELX_DOT_ALL : STOCKELX_DOT_NOT_ALL)
  );

 case RCHART('w'):
  return GetStockElx(flags & RIGHTTOLEFT ? STOCKELX_WORD_RIGHTLEFT : STOCKELX_WORD);

 case RCHART('W'):
  return GetStockElx(flags & RIGHTTOLEFT ? STOCKELX_WORD_RIGHTLEFT_NOT : STOCKELX_WORD_NOT);

 case RCHART('s'):
  return GetStockElx(flags & RIGHTTOLEFT ? STOCKELX_SPACE_RIGHTLEFT : STOCKELX_SPACE);

 case RCHART('S'):
  return GetStockElx(flags & RIGHTTOLEFT ? STOCKELX_SPACE_RIGHTLEFT_NOT : STOCKELX_SPACE_NOT);

 case RCHART('d'):
  return GetStockElx(flags & RIGHTTOLEFT ? STOCKELX_DIGITAL_RIGHTLEFT : STOCKELX_DIGITAL);

 case RCHART('D'):
  return GetStockElx(flags & RIGHTTOLEFT ? STOCKELX_DIGITAL_RIGHTLEFT_NOT : STOCKELX_DIGITAL_NOT);

 case RCHART('['):
  {
   CRangeElxT <CHART> * pRange;

   // create
   if(curr == CHART_INFO(RCHART(':'), 1))
   {
    CBufferT <char> posix;

    do {
     posix.Append(((curr.ch & (CHART)0xff) == curr.ch) ? (char)curr.ch : 0, 1);
     MoveNext();
    }
    while(curr.ch != RCHART(0) && curr != CHART_INFO(RCHART(']'), 1));

    MoveNext(); // skip ']'

    // posix
    return Keep(new CPosixElxT <CHART> (posix.GetBuffer(), flags & RIGHTTOLEFT));
   }
   else if(curr == CHART_INFO(RCHART('^'), 1))
   {
    MoveNext(); // skip '^'
    pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART> (flags & RIGHTTOLEFT, 0));
   }
   else
   {
    pRange = (CRangeElxT <CHART> *)Keep(new CRangeElxT <CHART> (flags & RIGHTTOLEFT, 1));
   }

   // parse
   while(curr != CHART_INFO(0, 1) && curr != CHART_INFO(RCHART(']'), 1))
   {
    ch = curr.ch;

    if(curr.type == 1 && (
     ch == RCHART('.') || ch == RCHART('w') || ch == RCHART('W') || ch == RCHART('s') || ch == RCHART('S') || ch == RCHART('d') || ch == RCHART('D') ||
     (ch == RCHART('[') && next == CHART_INFO(RCHART(':'), 1))
    ))
    {
     pRange->m_embeds.Push(BuildCharset(flags));
    }
    else if(next == CHART_INFO(RCHART('-'), 1) && nex2.type == 0)
    {
     pRange->m_ranges.Push(ch); pRange->m_ranges.Push(nex2.ch);

     // next
     MoveNext();
     MoveNext();
     MoveNext();
    }
    else
    {
     pRange->m_chars.Push(ch);

     // next
     MoveNext();
    }
   }

   // skip ']'
   MoveNext();

   if( flags & IGNORECASE )
   {
    CBufferT <CHART> & ranges = pRange->m_ranges;
    int i, oldcount = ranges.GetSize() / 2;

    for(i=0; i<oldcount; i++)
    {
     CHART newmin, newmax;

     if( ranges[i*2] <= RCHART('Z') && ranges[i*2+1] >= RCHART('A') )
     {
      newmin = tolower( max(RCHART('A'), ranges[i*2  ]) );
      newmax = tolower( min(RCHART('Z'), ranges[i*2+1]) );

      if( newmin < ranges[i*2] || newmax > ranges[i*2+1] )
      {
       ranges.Push(newmin);
       ranges.Push(newmax);
      }
     }

     if( ranges[i*2] <= RCHART('z') && ranges[i*2+1] >= RCHART('a') )
     {
      newmin = toupper( max(RCHART('a'), ranges[i*2  ]) );
      newmax = toupper( min(RCHART('z'), ranges[i*2+1]) );

      if( newmin < ranges[i*2] || newmax > ranges[i*2+1] )
      {
       ranges.Push(newmin);
       ranges.Push(newmax);
      }
     }
    }

    CBufferT <CHART> & chars = pRange->m_chars;
    oldcount = chars.GetSize();
    for(i=0; i<oldcount; i++)
    {
     if( isupper(chars[i]) && ! pRange->IsContainChar(tolower(chars[i])) )
      chars.Push(tolower(chars[i]));

     if( islower(chars[i]) && ! pRange->IsContainChar(toupper(chars[i])) )
      chars.Push(toupper(chars[i]));
    }
   }

   return pRange;
  }
 }

 return GetStockElx(STOCKELX_EMPTY);
}

template <class CHART> ElxInterface * CBuilderT <CHART> :: BuildRecursive(int & flags)
{
 // skip '('
 MoveNext();

 if(curr == CHART_INFO(RCHART('?'), 1))
 {
  ElxInterface * pElx = 0;

  // skip '?'
  MoveNext();

  int bNegative = 0;
  CHART named_end = RCHART('>');

  switch(curr.ch)
  {
  case RCHART('!'):
   bNegative = 1;

  case RCHART('='):
   {
    MoveNext(); // skip '!' or '='
    pElx = Keep(new CAssertElx(BuildAlternative(flags & ~RIGHTTOLEFT), !bNegative));
   }
   break;

  case RCHART('<'):
   switch(next.ch)
   {
   case RCHART('!'):
    bNegative = 1;

   case RCHART('='):
    MoveNext(); // skip '<'
    MoveNext(); // skip '!' or '='
    {
     pElx = Keep(new CAssertElx(BuildAlternative(flags | RIGHTTOLEFT), !bNegative));
    }
    break;

   default: // named group
    break;
   }
   // break if assertion // else named
   if(pElx != 0) break;

  case RCHART('P'):
   if(curr.ch == RCHART('P')) MoveNext(); // skip 'P'

  case RCHART('/''):
   if     (curr.ch == RCHART('<' )) named_end = RCHART('>' );
   else if(curr.ch == RCHART('/'')) named_end = RCHART('/'');
   MoveNext(); // skip '<' or '/''
   {
    // named number
    int nThisBackref = m_nNextNamed ++;

    CListElx    * pList  = (CListElx    *)Keep(new CListElx(flags & RIGHTTOLEFT));
    CBracketElx * pleft  = (CBracketElx *)Keep(new CBracketElx(-1, flags & RIGHTTOLEFT ? 1 : 0));
    CBracketElx * pright = (CBracketElx *)Keep(new CBracketElx(-1, flags & RIGHTTOLEFT ? 0 : 1));

    // save name
    CBufferT <CHART> & name = pleft->m_szNamed;
    CBufferT <char> num;

    while(curr.ch != RCHART(0) && curr.ch != named_end)
    {
     name.Append(curr.ch, 1);
     num .Append(((curr.ch & (CHART)0xff) == curr.ch) ? (char)curr.ch : 0, 1);
     MoveNext();
    }
    MoveNext(); // skip '>' or '/''

    // check <num>
    unsigned int number;
    char * str = num.GetBuffer();

    if( ReadDec(str, number) ? ( *str == '/0') : 0 )
    {
     pleft ->m_nnumber = number;
     pright->m_nnumber = number;

     name.Release();
    }

    // left, center, right
    pList->m_elxlist.Push(pleft);
    pList->m_elxlist.Push(BuildAlternative(flags));
    pList->m_elxlist.Push(pright);

    // for recursive
    m_namedlist.Prepare(nThisBackref);
    m_namedlist[nThisBackref] = pList;

    pElx = pList;
   }
   break;

  case RCHART('>'):
   {
    MoveNext(); // skip '>'
    pElx = Keep(new CIndependentElx(BuildAlternative(flags)));
   }
   break;

  case RCHART('R'):
   MoveNext(); // skip 'R'
   while(curr.ch != RCHART(0) && isspace(curr.ch)) MoveNext(); // skip space

   if(curr.ch == RCHART('<') || curr.ch == RCHART('/''))
   {
    named_end = curr.ch == RCHART('<') ? RCHART('>') : RCHART('/'');
    CDelegateElx * pDelegate = (CDelegateElx *)Keep(new CDelegateElx(-3));

    MoveNext(); // skip '<' or '//'

    // save name
    CBufferT <CHART> & name = pDelegate->m_szNamed;
    CBufferT <char> num;

    while(curr.ch != RCHART(0) && curr.ch != named_end)
    {
     name.Append(curr.ch, 1);
     num .Append(((curr.ch & (CHART)0xff) == curr.ch) ? (char)curr.ch : 0, 1);
     MoveNext();
    }
    MoveNext(); // skip '>' or '/''

    // check <num>
    unsigned int number;
    char * str = num.GetBuffer();

    if( ReadDec(str, number) ? ( *str == '/0') : 0 )
    {
     pDelegate->m_ndata = number;
     name.Release();
    }

    m_recursivelist.Push(pDelegate);
    pElx = pDelegate;
   }
   else
   {
    CBufferT <char> rto;
    while(curr.ch != RCHART(0) && curr.ch != RCHART(')'))
    {
     rto.Append(((curr.ch & (CHART)0xff) == curr.ch) ? (char)curr.ch : 0, 1);
     MoveNext();
    }

    unsigned int rtono = 0;
    char * str = rto.GetBuffer();
    ReadDec(str, rtono);

    CDelegateElx * pDelegate = (CDelegateElx *)Keep(new CDelegateElx(rtono));

    m_recursivelist.Push(pDelegate);
    pElx = pDelegate;
   }
   break;

  case RCHART('('):
   {
    CConditionElx * pConditionElx = (CConditionElx *)Keep(new CConditionElx());

    // condition
    ElxInterface * & pCondition = pConditionElx->m_pelxask;

    if(next == CHART_INFO(RCHART('?'), 1))
    {
     pCondition = BuildRecursive(flags);
    }
    else // named, assert or number
    {
     MoveNext(); // skip '('
     int pos0 = curr.pos;

     // save elx condition
     pCondition = Keep(new CAssertElx(BuildAlternative(flags), 1));

     // save name
     pConditionElx->m_szNamed.Append(m_pattern.GetBuffer() + pos0, curr.pos - pos0, 1);

     // save number
     CBufferT <char> numstr;
     while(pos0 < curr.pos)
     {
      CHART ch = m_pattern[pos0];
      numstr.Append(((ch & (CHART)0xff) == ch) ? (char)ch : 0, 1);
      pos0 ++;
     }

     unsigned int number;
     char * str = numstr.GetBuffer();

     // valid group number
     if( ReadDec(str, number) ? ( *str == '/0') : 0 )
     {
      pConditionElx->m_nnumber = number;
      pCondition = 0;
     }
     else // maybe elx, maybe named
     {
      pConditionElx->m_nnumber = -1;
      m_namedconditionlist.Push(pConditionElx);
     }

     MoveNext(); // skip ')'
    }

    // alternative
    {
     int newflags = flags;

     pConditionElx->m_pelxyes = BuildList(newflags);
    }

    if(curr.ch == RCHART('|'))
    {
     MoveNext(); // skip '|'

     pConditionElx->m_pelxno = BuildAlternative(flags);
    }
    else
    {
     pConditionElx->m_pelxno = 0;
    }

    pElx = pConditionElx;
   }
   break;

  default:
   while(curr.ch != RCHART(0) && isspace(curr.ch)) MoveNext(); // skip space

   if(curr.ch >= RCHART('0') && curr.ch <= RCHART('9')) // recursive (?1) => (?R1)
   {
    CBufferT <char> rto;
    while(curr.ch != RCHART(0) && curr.ch != RCHART(')'))
    {
     rto.Append(((curr.ch & (CHART)0xff) == curr.ch) ? (char)curr.ch : 0, 1);
     MoveNext();
    }

    unsigned int rtono = 0;
    char * str = rto.GetBuffer();
    ReadDec(str, rtono);

    CDelegateElx * pDelegate = (CDelegateElx *)Keep(new CDelegateElx(rtono));

    m_recursivelist.Push(pDelegate);
    pElx = pDelegate;
   }
   else
   {
    // flag
    int newflags = flags;
    while(curr != CHART_INFO(0, 1) && curr.ch != RCHART(':') && curr.ch != RCHART(')') && curr != CHART_INFO(RCHART('('), 1))
    {
     int tochange = 0;

     switch(curr.ch)
     {
     case RCHART('i'):
     case RCHART('I'):
      tochange = IGNORECASE;
      break;

     case RCHART('s'):
     case RCHART('S'):
      tochange = SINGLELINE;
      break;

     case RCHART('m'):
     case RCHART('M'):
      tochange = MULTILINE;
      break;

     case RCHART('g'):
     case RCHART('G'):
      tochange = GLOBAL;
      break;

     case RCHART('-'):
      bNegative = 1;
      break;
     }

     if(bNegative)
      newflags &= ~tochange;
     else
      newflags |=  tochange;

     // move to next char
     MoveNext();
    }

    if(curr.ch == RCHART(':') || curr == CHART_INFO(RCHART('('), 1))
    {
     // skip ':'
     if(curr.ch == RCHART(':')) MoveNext();

     pElx = BuildAlternative(newflags);
    }
    else
    {
     // change parent flags
     flags = newflags;

     pElx = GetStockElx(STOCKELX_EMPTY);
    }
   }
   break;
  }

  MoveNext(); // skip ')'

  return pElx;
 }
 else
 {
  // group and number
  CListElx * pList = (CListElx *)Keep(new CListElx(flags & RIGHTTOLEFT));
  int nThisBackref = ++ m_nMaxNumber;

  // left, center, right
  pList->m_elxlist.Push(Keep(new CBracketElx(nThisBackref, flags & RIGHTTOLEFT ? 1 : 0)));
  pList->m_elxlist.Push(BuildAlternative(flags));
  pList->m_elxlist.Push(Keep(new CBracketElx(nThisBackref, flags & RIGHTTOLEFT ? 0 : 1)));

  // for recursive
  m_grouplist.Prepare(nThisBackref);
  m_grouplist[nThisBackref] = pList;

  // right
  MoveNext(); // skip ')'

  return pList;
 }
}

template <class CHART> ElxInterface * CBuilderT <CHART> :: BuildBoundary(int & flags)
{
 // char
 CHART ch = curr.ch;

 // skip
 MoveNext();

 switch(ch)
 {
 case RCHART('^'):
  return Keep(new CBoundaryElxT <CHART> ((flags & MULTILINE) ? BOUNDARY_LINE_BEGIN : BOUNDARY_FILE_BEGIN));

 case RCHART('$'):
  return Keep(new CBoundaryElxT <CHART> ((flags & MULTILINE) ? BOUNDARY_LINE_END : BOUNDARY_FILE_END));

 case RCHART('b'):
  return Keep(new CBoundaryElxT <CHART> (BOUNDARY_WORD_EDGE));

 case RCHART('B'):
  return Keep(new CBoundaryElxT <CHART> (BOUNDARY_WORD_EDGE, 0));

 case RCHART('A'):
  return Keep(new CBoundaryElxT <CHART> (BOUNDARY_FILE_BEGIN));

 case RCHART('Z'):
  return Keep(new CBoundaryElxT <CHART> (BOUNDARY_FILE_END_N));

 case RCHART('z'):
  return Keep(new CBoundaryElxT <CHART> (BOUNDARY_FILE_END));

 case RCHART('G'):
  if(flags & GLOBAL)
   return Keep(new CGlobalElx());
  else
   return GetStockElx(STOCKELX_EMPTY);

 default:
  return GetStockElx(STOCKELX_EMPTY);
 }
}

template <class CHART> ElxInterface * CBuilderT <CHART> :: BuildBackref(int & flags)
{
 // skip '//' or '/k' or '/g'
 MoveNext();

 if(curr.ch == RCHART('<') || curr.ch == RCHART('/''))
 {
  CHART named_end = curr.ch == RCHART('<') ? RCHART('>') : RCHART('/'');
  CBackrefElxT <CHART> * pbackref = (CBackrefElxT <CHART> *)Keep(new CBackrefElxT <CHART> (-1, flags & RIGHTTOLEFT, flags & IGNORECASE));

  MoveNext(); // skip '<' or '/''

  // save name
  CBufferT <CHART> & name = pbackref->m_szNamed;
  CBufferT <char> num;

  while(curr.ch != RCHART(0) && curr.ch != named_end)
  {
   name.Append(curr.ch, 1);
   num .Append(((curr.ch & (CHART)0xff) == curr.ch) ? (char)curr.ch : 0, 1);
   MoveNext();
  }
  MoveNext(); // skip '>' or '/''

  // check <num>
  unsigned int number;
  char * str = num.GetBuffer();

  if( ReadDec(str, number) ? ( *str == '/0') : 0 )
  {
   pbackref->m_nnumber = number;
   name.Release();
  }
  else
  {
   m_namedbackreflist.Push(pbackref);
  }

  return pbackref;
 }
 else
 {
  unsigned int nbackref = 0;

  for(int i=0; i<3; i++)
  {
   if(curr.ch >= RCHART('0') && curr.ch <= RCHART('9'))
    nbackref = nbackref * 10 + (curr.ch - RCHART('0'));
   else
    break;

   MoveNext();
  }

  return Keep(new CBackrefElxT <CHART> (nbackref, flags & RIGHTTOLEFT, flags & IGNORECASE));
 }
}

template <class CHART> int CBuilderT <CHART> :: ReadDec(char * & str, unsigned int & dec)
{
 int s = 0;
 while(str[s] != 0 && isspace(str[s])) s++;

 if(str[s] < '0' || str[s] > '9') return 0;

 dec = 0;
 unsigned int i;

 for(i = s; i<sizeof(CHART)*3 + s; i++)
 {
  if(str[i] >= '0' && str[i] <= '9')
   dec = dec * 10 + (str[i] - '0');
  else
   break;
 }

 while(str[i] != 0 && isspace(str[i])) i++;
 str += i;

 return 1;
}

//
// Regexp
//
template <class CHART> class CRegexpT
{
public:
 CRegexpT(const CHART * pattern = 0, int flags = 0);
 CRegexpT(const CHART * pattern, int length, int flags);
 void Compile(const CHART * pattern, int flags = 0);
 void Compile(const CHART * pattern, int length, int flags);

public:
 MatchResult MatchExact(const CHART * tstring, CContext * pContext = 0) const;
 MatchResult MatchExact(const CHART * tstring, int length, CContext * pContext = 0) const;
 MatchResult Match(const CHART * tstring, int start = -1, CContext * pContext = 0) const;
 MatchResult Match(const CHART * tstring, int length, int start, CContext * pContext = 0) const;
 MatchResult Match(CContext * pContext) const;
 CContext * PrepareMatch(const CHART * tstring, int start = -1, CContext * pContext = 0) const;
 CContext * PrepareMatch(const CHART * tstring, int length, int start, CContext * pContext = 0) const;
 CHART * Replace(const CHART * tstring, const CHART * replaceto, int start = -1, int ntimes = -1, MatchResult * result = 0, CContext * pContext = 0) const;
 CHART * Replace(const CHART * tstring, int string_length, const CHART * replaceto, int to_length, int & result_length, int start = -1, int ntimes = -1, MatchResult * result = 0, CContext * pContext = 0) const;
 int GetNamedGroupNumber(const CHART * group_name) const;

public:
 static void ReleaseString (CHART    * tstring );
 static void ReleaseContext(CContext * pContext);

public:
 CBuilderT <CHART> m_builder;
};

//
// Implementation
//
template <class CHART> CRegexpT <CHART> :: CRegexpT(const CHART * pattern, int flags)
{
 Compile(pattern, CBufferRefT<CHART>(pattern).GetSize(), flags);
}

template <class CHART> CRegexpT <CHART> :: CRegexpT(const CHART * pattern, int length, int flags)
{
 Compile(pattern, length, flags);
}

template <class CHART> inline void CRegexpT <CHART> :: Compile(const CHART * pattern, int flags)
{
 Compile(pattern, CBufferRefT<CHART>(pattern).GetSize(), flags);
}

template <class CHART> void CRegexpT <CHART> :: Compile(const CHART * pattern, int length, int flags)
{
 m_builder.Clear();
 if(pattern != 0) m_builder.Build(CBufferRefT<CHART>(pattern, length), flags);
}

template <class CHART> inline MatchResult CRegexpT <CHART> :: MatchExact(const CHART * tstring, CContext * pContext) const
{
 return MatchExact(tstring, CBufferRefT<CHART>(tstring).GetSize(), pContext);
}

template <class CHART> MatchResult CRegexpT <CHART> :: MatchExact(const CHART * tstring, int length, CContext * pContext) const
{
 if(m_builder.m_pTopElx == 0)
  return 0;

 // info
 int endpos = 0;

 CContext context;
 if(pContext == 0) pContext = &context;

 pContext->m_stack.Restore(0);
 pContext->m_capturestack.Restore(0);
 pContext->m_captureindex.Restore(0);

 pContext->m_nParenZindex  = 0;
 pContext->m_nLastBeginPos = -1;
 pContext->m_pMatchString  = (void*)tstring;
 pContext->m_pMatchStringLength = length;

 if(m_builder.m_nFlags & RIGHTTOLEFT)
 {
  pContext->m_nBeginPos   = length;
  pContext->m_nCurrentPos = length;
  endpos = 0;
 }
 else
 {
  pContext->m_nBeginPos   = 0;
  pContext->m_nCurrentPos = 0;
  endpos = length;
 }

 pContext->m_captureindex.Prepare(m_builder.m_nMaxNumber, -1);
 pContext->m_captureindex[0] = 0;
 pContext->m_capturestack.Push(0);
 pContext->m_capturestack.Push(pContext->m_nCurrentPos);
 pContext->m_capturestack.Push(-1);
 pContext->m_capturestack.Push(-1);

 // match
 if( ! m_builder.m_pTopElx->Match( pContext ) )
  return 0;
 else
 {
  while( pContext->m_nCurrentPos != endpos )
  {
   if( ! m_builder.m_pTopElx->MatchNext( pContext ) )
    return 0;
   else
   {
    if( pContext->m_nLastBeginPos == pContext->m_nBeginPos && pContext->m_nBeginPos == pContext->m_nCurrentPos )
     return 0;
    else
     pContext->m_nLastBeginPos = pContext->m_nCurrentPos;
   }
  }

  // end pos
  pContext->m_capturestack[2] = pContext->m_nCurrentPos;

  return MatchResult( pContext, m_builder.m_nMaxNumber );
 }
}

template <class CHART> MatchResult CRegexpT <CHART> :: Match(const CHART * tstring, int start, CContext * pContext) const
{
 return Match(tstring, CBufferRefT<CHART>(tstring).GetSize(), start, pContext);
}

template <class CHART> MatchResult CRegexpT <CHART> :: Match(const CHART * tstring, int length, int start, CContext * pContext) const
{
 if(m_builder.m_pTopElx == 0)
  return 0;

 CContext context;
 if(pContext == 0) pContext = &context;

 PrepareMatch(tstring, length, start, pContext);

 return Match( pContext );
}

template <class CHART> MatchResult CRegexpT <CHART> :: Match(CContext * pContext) const
{
 if(m_builder.m_pTopElx == 0)
  return 0;

 int endpos, delta;

 if(m_builder.m_nFlags & RIGHTTOLEFT)
 {
  endpos = -1;
  delta  = -1;
 }
 else
 {
  endpos = pContext->m_pMatchStringLength + 1;
  delta  = 1;
 }

 while(pContext->m_nCurrentPos != endpos)
 {
  pContext->m_captureindex.Restore(0);
  pContext->m_stack       .Restore(0);
  pContext->m_capturestack.Restore(0);

  pContext->m_captureindex.Prepare(m_builder.m_nMaxNumber, -1);
  pContext->m_captureindex[0] = 0;
  pContext->m_capturestack.Push(0);
  pContext->m_capturestack.Push(pContext->m_nCurrentPos);
  pContext->m_capturestack.Push(-1);
  pContext->m_capturestack.Push(-1);

  if( m_builder.m_pTopElx->Match( pContext ) )
  {
   pContext->m_capturestack[2] = pContext->m_nCurrentPos;

   // zero width
   if( /* pContext->m_nLastBeginPos == pContext->m_nBeginPos && */ pContext->m_nBeginPos == pContext->m_nCurrentPos )
   {
    pContext->m_nCurrentPos += delta;
    /* continue; */
   }

   // save pos
   pContext->m_nLastBeginPos   = pContext->m_nBeginPos;
   pContext->m_nBeginPos       = pContext->m_nCurrentPos;

   // return
   return MatchResult( pContext, m_builder.m_nMaxNumber );
  }
  else
  {
   pContext->m_nCurrentPos += delta;
  }
 }

 return 0;
}

template <class CHART> inline CContext * CRegexpT <CHART> :: PrepareMatch(const CHART * tstring, int start, CContext * pContext) const
{
 return PrepareMatch(tstring, CBufferRefT<CHART>(tstring).GetSize(), start, pContext);
}

template <class CHART> CContext * CRegexpT <CHART> :: PrepareMatch(const CHART * tstring, int length, int start, CContext * pContext) const
{
 if(m_builder.m_pTopElx == 0)
  return 0;

 if(pContext == 0) pContext = new CContext();

 pContext->m_nParenZindex  =  0;
 pContext->m_nLastBeginPos = -1;
 pContext->m_pMatchString  = (void*)tstring;
 pContext->m_pMatchStringLength = length;

 if(start < 0)
 {
  if(m_builder.m_nFlags & RIGHTTOLEFT)
  {
   pContext->m_nBeginPos   = length;
   pContext->m_nCurrentPos = length;
  }
  else
  {
   pContext->m_nBeginPos   = 0;
   pContext->m_nCurrentPos = 0;
  }
 }
 else
 {
  if(start > length) start = length + ((m_builder.m_nFlags & RIGHTTOLEFT)?0:1);

  pContext->m_nBeginPos   = start;
  pContext->m_nCurrentPos = start;
 }

 return pContext;
}

template <class CHART> inline int CRegexpT <CHART> :: GetNamedGroupNumber(const CHART * group_name) const
{
 return m_builder.GetNamedNumber(group_name);
}

template <class CHART> CHART * CRegexpT <CHART> :: Replace(const CHART * tstring, const CHART * replaceto, int start, int ntimes, MatchResult * result, CContext * pContext) const
{
 int result_length = 0;
 return Replace(tstring, CBufferRefT<CHART>(tstring).GetSize(), replaceto, CBufferRefT<CHART>(replaceto).GetSize(), result_length, start, ntimes, result, pContext);
}

template <class CHART> CHART * CRegexpT <CHART> :: Replace(const CHART * tstring, int string_length, const CHART * replaceto, int to_length, int & result_length, int start, int ntimes, MatchResult * remote_result, CContext * oContext) const
{
 if(m_builder.m_pTopElx == 0) return 0;

 // --- compile replace to ---

 CBufferT <int> compiledto;

 static const CHART rtoptn[] = { RCHART('//'), RCHART('$' ), RCHART('('), RCHART('?'), RCHART(':'), RCHART('[' ), RCHART('$' ), RCHART('&' ), RCHART('`' ), RCHART('/''), RCHART('+'), RCHART('_' ), RCHART('//'), RCHART('d'), RCHART(']'), RCHART('|'), RCHART('//'), RCHART('{'), RCHART('.'), RCHART('*'), RCHART('?'), RCHART('//'), RCHART('}'), RCHART(')' ), RCHART('/0') };
 static CRegexpT <CHART> rtoreg(rtoptn);

 MatchResult local_result(0), * result = remote_result ? remote_result : & local_result;

 // prepare
 CContext * pContext = PrepareMatch(replaceto, to_length, -1, oContext);
 int lastIndex = 0, nmatch = 0;

 while( ((*result) = rtoreg.Match(pContext)).IsMatched() )
 {
  int delta = result->GetStart() - lastIndex;
  if( delta > 0 )
  {
   compiledto.Push(lastIndex);
   compiledto.Push(delta);
  }

  lastIndex = result->GetStart();
  delta     = 2;

  switch(replaceto[lastIndex + 1])
  {
  case RCHART('$'):
   compiledto.Push(lastIndex);
   compiledto.Push(1);
   break;

  case RCHART('&'):
  case RCHART('`'):
  case RCHART('/''):
  case RCHART('+'):
  case RCHART('_'):
   compiledto.Push(-1);
   compiledto.Push((int)replaceto[lastIndex + 1]);
   break;

  case RCHART('{'):
   delta  = result->GetEnd() - result->GetStart();
   nmatch = m_builder.GetNamedNumber(CBufferRefT <CHART> (replaceto + (lastIndex + 2), delta - 3));

   if(nmatch > 0 && nmatch <= m_builder.m_nMaxNumber)
   {
    compiledto.Push(-2);
    compiledto.Push(nmatch);
   }
   else
   {
    compiledto.Push(lastIndex);
    compiledto.Push(delta);
   }
   break;

  default:
   nmatch = 0;
   for(delta=1; delta<=3; delta++)
   {
    CHART ch = replaceto[lastIndex + delta];

    if(ch < RCHART('0') || ch > RCHART('9'))
     break;

    nmatch = nmatch * 10 + (ch - RCHART('0'));
   }

   if(nmatch > m_builder.m_nMaxNumber)
   {
    while(nmatch > m_builder.m_nMaxNumber)
    {
     nmatch /= 10;
     delta --;
    }

    if(nmatch == 0)
    {
     delta = 1;
    }
   }

   if(delta == 1)
   {
    compiledto.Push(lastIndex);
    compiledto.Push(1);
   }
   else
   {
    compiledto.Push(-2);
    compiledto.Push(nmatch);
   }
   break;
  }

  lastIndex += delta;
 }

 if(lastIndex < to_length)
 {
  compiledto.Push(lastIndex);
  compiledto.Push(to_length - lastIndex);
 }

 int rightleft = m_builder.m_nFlags & RIGHTTOLEFT;

 int tb = rightleft ? compiledto.GetSize() - 2 : 0;
 int te = rightleft ? -2 : compiledto.GetSize();
 int ts = rightleft ? -2 : 2;

 // --- compile complete ---

 int beginpos  = rightleft ? string_length : 0;
 int endpos    = rightleft ? 0 : string_length;

 int toIndex0  = 0;
 int toIndex1  = 0;
 int i, ntime;

 CBufferT <const CHART *> buffer;

 // prepare
 pContext  = PrepareMatch(tstring, string_length, start, pContext);
 lastIndex = beginpos;

 // Match
 for(ntime = 0; ntimes < 0 || ntime < ntimes; ntime ++)
 {
  (*result) = Match(pContext);

  if( ! result->IsMatched() )
   break;

  // before
  if( rightleft )
  {
   int distance = lastIndex - result->GetEnd();
   if( distance )
   {
    buffer.Push(tstring + result->GetEnd());
    buffer.Push((const CHART *)distance);

    toIndex1 -= distance;
   }
   lastIndex = result->GetStart();
  }
  else
  {
   int distance = result->GetStart() - lastIndex;
   if( distance )
   {
    buffer.Push(tstring + lastIndex);
    buffer.Push((const CHART *)distance);

    toIndex1 += distance;
   }
   lastIndex = result->GetEnd();
  }

  toIndex0 = toIndex1;

  // middle
  for(i=tb; i!=te; i+=ts)
  {
   int off = compiledto[i];
   int len = compiledto[i + 1];

   const CHART * sub = replaceto + off;

   if( off == -1 )
   {
    switch(RCHART(len))
    {
    case RCHART('&'):
     sub = tstring + result->GetStart();
     len = result->GetEnd() - result->GetStart();
     break;

    case RCHART('`'):
     sub = tstring;
     len = result->GetStart();
     break;

    case RCHART('/''):
     sub = tstring + result->GetEnd();
     len = string_length - result->GetEnd();
     break;

    case RCHART('+'):
     for(nmatch = result->MaxGroupNumber(); nmatch >= 0; nmatch --)
     {
      if(result->GetGroupStart(nmatch) >= 0) break;
     }
     sub = tstring + result->GetGroupStart(nmatch);
     len = result->GetGroupEnd(nmatch) - result->GetGroupStart(nmatch);
     break;

    case RCHART('_'):
     sub = tstring;
     len = string_length;
     break;
    }
   }
   else if( off == -2 )
   {
    sub = tstring + result->GetGroupStart(len);
    len = result->GetGroupEnd(len) - result->GetGroupStart(len);
   }

   buffer.Push(sub);
   buffer.Push((const CHART *)len);

   toIndex1 += rightleft ? (-len) : len;
  }
 }

 // after
 if(rightleft)
 {
  if(endpos < lastIndex)
  {
   buffer.Push(tstring + endpos);
   buffer.Push((const CHART *)(lastIndex - endpos));
  }
 }
 else
 {
  if(lastIndex < endpos)
  {
   buffer.Push(tstring + lastIndex);
   buffer.Push((const CHART *)(endpos - lastIndex));
  }
 }

 if(oContext == 0) ReleaseContext(pContext);

 // join string
 result_length = 0;
 for(i=0; i<buffer.GetSize(); i+=2)
 {
  result_length += (int)buffer[i+1];
 }

 CBufferT <CHART> result_string;
 result_string.Prepare(result_length);
 result_string.Restore(0);

 if(rightleft)
 {
  for(i=buffer.GetSize()-2; i>=0; i-=2)
  {
   result_string.Append(buffer[i], (int)buffer[i+1]);
  }
 }
 else
 {
  for(i=0; i<buffer.GetSize(); i+=2)
  {
   result_string.Append(buffer[i], (int)buffer[i+1]);
  }
 }

 result_string.Append(0);

 result->m_result.Append(result_length, 3);
 result->m_result.Append(ntime);

 if(rightleft)
 {
  result->m_result.Append(result_length - toIndex1);
  result->m_result.Append(result_length - toIndex0);
 }
 else
 {
  result->m_result.Append(toIndex0);
  result->m_result.Append(toIndex1);
 }

 return result_string.Detach();
}

template <class CHART> inline void CRegexpT <CHART> :: ReleaseString(CHART * tstring)
{
 if(tstring != 0) free(tstring);
}

template <class CHART> inline void CRegexpT <CHART> :: ReleaseContext(CContext * pContext)
{
 if(pContext != 0) delete pContext;
}

//
// All implementations
//
template <int x> CAlternativeElxT <x> :: CAlternativeElxT()
{
}

template <int x> int CAlternativeElxT <x> :: Match(CContext * pContext) const
{
 if(m_elxlist.GetSize() == 0)
  return 1;

 // try all
 for(int n = 0; n < m_elxlist.GetSize(); n++)
 {
  if(m_elxlist[n]->Match(pContext))
  {
   pContext->m_stack.Push(n);
   return 1;
  }
 }

 return 0;
}

template <int x> int CAlternativeElxT <x> :: MatchNext(CContext * pContext) const
{
 if(m_elxlist.GetSize() == 0)
  return 0;

 int n = 0;

 // recall prev
 pContext->m_stack.Pop(n);

 // prev
 if(m_elxlist[n]->MatchNext(pContext))
 {
  pContext->m_stack.Push(n);
  return 1;
 }
 else
 {
  // try rest
  for(n++; n < m_elxlist.GetSize(); n++)
  {
   if(m_elxlist[n]->Match(pContext))
   {
    pContext->m_stack.Push(n);
    return 1;
   }
  }

  return 0;
 }
}

// assertx.cpp: implementation of the CAssertElx class.
//
template <int x> CAssertElxT <x> :: CAssertElxT(ElxInterface * pelx, int byes)
{
 m_pelx = pelx;
 m_byes = byes;
}

template <int x> int CAssertElxT <x> :: Match(CContext * pContext) const
{
 int nbegin = pContext->m_nCurrentPos;
 int nsize  = pContext->m_stack.GetSize();
 int ncsize = pContext->m_capturestack.GetSize();
 int bsucc;

 // match
 if( m_byes )
  bsucc =   m_pelx->Match(pContext);
 else
  bsucc = ! m_pelx->Match(pContext);

 // status
 pContext->m_stack.Restore(nsize);
 pContext->m_nCurrentPos = nbegin;

 if( bsucc )
  pContext->m_stack.Push(ncsize);
 else
  pContext->m_capturestack.Restore(ncsize);

 return bsucc;
}

template <int x> int CAssertElxT <x> :: MatchNext(CContext * pContext) const
{
 int ncsize = 0;

 pContext->m_stack.Pop(ncsize);
 pContext->m_capturestack.Restore(ncsize);

 return 0;
}

// emptyelx.cpp: implementation of the CEmptyElx class.
//
template <int x> CEmptyElxT <x> :: CEmptyElxT()
{
}

template <int x> int CEmptyElxT <x> :: Match(CContext *) const
{
 return 1;
}

template <int x> int CEmptyElxT <x> :: MatchNext(CContext *) const
{
 return 0;
}

// globalx.cpp: implementation of the CGlobalElx class.
//
template <int x> CGlobalElxT <x> ::CGlobalElxT()
{
}

template <int x> int CGlobalElxT <x> :: Match(CContext * pContext) const
{
 return pContext->m_nCurrentPos == pContext->m_nBeginPos;
}

template <int x> int CGlobalElxT <x> :: MatchNext(CContext *) const
{
 return 0;
}

// greedelx.cpp: implementation of the CGreedyElx class.
//
template <int x> CGreedyElxT <x> :: CGreedyElxT(ElxInterface * pelx, int nmin, int nmax) : CRepeatElxT <x> (pelx, nmin)
{
 m_nvart = nmax - nmin;
}

template <int x> int CGreedyElxT <x> :: Match(CContext * pContext) const
{
 if( ! CRepeatElxT <x> :: MatchFixed(pContext) )
  return 0;

 while( ! MatchVart(pContext) )
 {
  if( ! CRepeatElxT <x> :: MatchNextFixed(pContext) )
   return 0;
 }

 return 1;
}

template <int x> int CGreedyElxT <x> :: MatchNext(CContext * pContext) const
{
 if( MatchNextVart(pContext) )
  return 1;

 if( ! CRepeatElxT <x> :: MatchNextFixed(pContext) )
  return 0;

 while( ! MatchVart(pContext) )
 {
  if( ! CRepeatElxT <x> :: MatchNextFixed(pContext) )
   return 0;
 }

 return 1;
}

template <int x> int CGreedyElxT <x> :: MatchVart(CContext * pContext) const
{
 int n      = 0;
 int nbegin = pContext->m_nCurrentPos;

 while(n < m_nvart && CRepeatElxT <x> :: m_pelx->Match(pContext))
 {
  while(pContext->m_nCurrentPos == nbegin)
  {
   if( ! CRepeatElxT <x> :: m_pelx->MatchNext(pContext) ) break;
  }

  if(pContext->m_nCurrentPos == nbegin) break;

  n ++;
  nbegin = pContext->m_nCurrentPos;
 }

 pContext->m_stack.Push(n);

 return 1;
}

template <int x> int CGreedyElxT <x> :: MatchNextVart(CContext * pContext) const
{
 int n = 0;
 pContext->m_stack.Pop(n);

 if(n == 0) return 0;

 if( ! CRepeatElxT <x> :: m_pelx->MatchNext(pContext) )
 {
  n --;
 }

 pContext->m_stack.Push(n);

 return 1;
}

// indepelx.cpp: implementation of the CIndependentElx class.
//
template <int x> CIndependentElxT <x> :: CIndependentElxT(ElxInterface * pelx)
{
 m_pelx = pelx;
}

template <int x> int CIndependentElxT <x> :: Match(CContext * pContext) const
{
 int nbegin = pContext->m_nCurrentPos;
 int nsize  = pContext->m_stack.GetSize();
 int ncsize = pContext->m_capturestack.GetSize();

 // match
 int bsucc  = m_pelx->Match(pContext);

 // status
 pContext->m_stack.Restore(nsize);

 if( bsucc )
 {
  pContext->m_stack.Push(nbegin);
  pContext->m_stack.Push(ncsize);
 }

 return bsucc;
}

template <int x> int CIndependentElxT <x> :: MatchNext(CContext * pContext) const
{
 int nbegin = 0, ncsize = 0;

 pContext->m_stack.Pop(ncsize);
 pContext->m_stack.Pop(nbegin);

 pContext->m_capturestack.Restore(ncsize);
 pContext->m_nCurrentPos = nbegin;

 return 0;
}

// listelx.cpp: implementation of the CListElx class.
//
template <int x> CListElxT <x> :: CListElxT(int brightleft)
{
 m_brightleft = brightleft;
}

template <int x> int CListElxT <x> :: Match(CContext * pContext) const
{
 if(m_elxlist.GetSize() == 0)
  return 1;

 // prepare
 int bol = m_brightleft ? m_elxlist.GetSize() : -1;
 int stp = m_brightleft ? -1 : 1;
 int eol = m_brightleft ? -1 : m_elxlist.GetSize();

 // from first
 int n = bol + stp;

 // match all
 while(n != eol)
 {
  if(m_elxlist[n]->Match(pContext))
  {
   n += stp;
  }
  else
  {
   n -= stp;

   while(n != bol && ! m_elxlist[n]->MatchNext(pContext))
    n -= stp;

   if(n != bol)
    n += stp;
   else
    return 0;
  }
 }

 return 1;
}

template <int x> int CListElxT <x> :: MatchNext(CContext * pContext) const
{
 if(m_elxlist.GetSize() == 0)
  return 0;

 // prepare
 int bol = m_brightleft ? m_elxlist.GetSize() : -1;
 int stp = m_brightleft ? -1 : 1;
 int eol = m_brightleft ? -1 : m_elxlist.GetSize();

 // from last
 int n = eol - stp;

 while(n != bol && ! m_elxlist[n]->MatchNext(pContext))
  n -= stp;

 if(n != bol)
  n += stp;
 else
  return 0;

 // match rest
 while(n != eol)
 {
  if(m_elxlist[n]->Match(pContext))
  {
   n += stp;
  }
  else
  {
   n -= stp;

   while(n != bol && ! m_elxlist[n]->MatchNext(pContext))
    n -= stp;

   if(n != bol)
    n += stp;
   else
    return 0;
  }
 }

 return 1;
}

// mresult.cpp: implementation of the MatchResult class.
//
template <int x> MatchResultT <x> :: MatchResultT(CContext * pContext, int nMaxNumber)
{
 if(pContext != 0)
 {
  m_result.Prepare(nMaxNumber * 2 + 3, -1);

  // matched
  m_result[0] = 1;
  m_result[1] = nMaxNumber;

  for(int n = 0; n <= nMaxNumber; n++)
  {
   int index = pContext->m_captureindex[n];
   if( index < 0 ) continue;

   // check enclosed
   int pos1 = pContext->m_capturestack[index + 1];
   int pos2 = pContext->m_capturestack[index + 2];

   // info
   m_result[n*2 + 2] = pos1 < pos2 ? pos1 : pos2;
   m_result[n*2 + 3] = pos1 < pos2 ? pos2 : pos1;
  }
 }
}

template <int x> inline int MatchResultT <x> :: IsMatched() const
{
 return m_result.At(0, 0);
}

template <int x> inline int MatchResultT <x> :: MaxGroupNumber() const
{
 return m_result.At(1, 0);
}

template <int x> inline int MatchResultT <x> :: GetStart() const
{
 return m_result.At(2, -1);
}

template <int x> inline int MatchResultT <x> :: GetEnd() const
{
 return m_result.At(3, -1);
}

template <int x> inline int MatchResultT <x> :: GetGroupStart(int nGroupNumber) const
{
 return m_result.At(2 + nGroupNumber * 2, -1);
}

template <int x> inline int MatchResultT <x> :: GetGroupEnd(int nGroupNumber) const
{
 return m_result.At(2 + nGroupNumber * 2 + 1, -1);
}

template <int x> MatchResultT <x> & MatchResultT <x> :: operator = (const MatchResultT <x> & result)
{
 m_result.Restore(0);
 if(result.m_result.GetSize() > 0) m_result.Append(result.m_result.GetBuffer(), result.m_result.GetSize());

 return *this;
}

// posselx.cpp: implementation of the CPossessiveElx class.
//
template <int x> CPossessiveElxT <x> :: CPossessiveElxT(ElxInterface * pelx, int nmin, int nmax) : CGreedyElxT <x> (pelx, nmin, nmax)
{
}

template <int x> int CPossessiveElxT <x> :: Match(CContext * pContext) const
{
 int nbegin = pContext->m_nCurrentPos;
 int nsize  = pContext->m_stack.GetSize();
 int ncsize = pContext->m_capturestack.GetSize();
 int bsucc  = 1;

 // match
 if( ! CRepeatElxT <x> :: MatchFixed(pContext) )
 {
  bsucc = 0;
 }
 else
 {
  while( ! CGreedyElxT <x> :: MatchVart(pContext) )
  {
   if( ! CRepeatElxT <x> :: MatchNextFixed(pContext) )
   {
    bsucc = 0;
    break;
   }
  }
 }

 // status
 pContext->m_stack.Restore(nsize);

 if( bsucc )
 {
  pContext->m_stack.Push(nbegin);
  pContext->m_stack.Push(ncsize);
 }

 return bsucc;
}

template <int x> int CPossessiveElxT <x> :: MatchNext(CContext * pContext) const
{
 int nbegin = 0, ncsize = 0;

 pContext->m_stack.Pop(ncsize);
 pContext->m_stack.Pop(nbegin);

 pContext->m_capturestack.Restore(ncsize);
 pContext->m_nCurrentPos = nbegin;

 return 0;
}

// reluctx.cpp: implementation of the CReluctantElx class.
//
template <int x> CReluctantElxT <x> :: CReluctantElxT(ElxInterface * pelx, int nmin, int nmax) : CRepeatElxT <x> (pelx, nmin)
{
 m_nvart = nmax - nmin;
}

template <int x> int CReluctantElxT <x> :: Match(CContext * pContext) const
{
 if( ! CRepeatElxT <x> :: MatchFixed(pContext) )
  return 0;

 while( ! MatchVart(pContext) )
 {
  if( ! CRepeatElxT <x> :: MatchNextFixed(pContext) )
   return 0;
 }

 return 1;
}

template <int x> int CReluctantElxT <x> :: MatchNext(CContext * pContext) const
{
 if( MatchNextVart(pContext) )
  return 1;

 if( ! CRepeatElxT <x> :: MatchNextFixed(pContext) )
  return 0;

 while( ! MatchVart(pContext) )
 {
  if( ! CRepeatElxT <x> :: MatchNextFixed(pContext) )
   return 0;
 }

 return 1;
}

template <int x> int CReluctantElxT <x> :: MatchVart(CContext * pContext) const
{
 pContext->m_stack.Push(0);

 return 1;
}

template <int x> int CReluctantElxT <x> :: MatchNextVart(CContext * pContext) const
{
 int n = 0, nbegin = pContext->m_nCurrentPos;

 pContext->m_stack.Pop(n);

 if(n < m_nvart && CRepeatElxT <x> :: m_pelx->Match(pContext))
 {
  while(pContext->m_nCurrentPos == nbegin)
  {
   if( ! CRepeatElxT <x> :: m_pelx->MatchNext(pContext) ) break;
  }

  if(pContext->m_nCurrentPos != nbegin)
  {
   n ++;

   pContext->m_stack.Push(nbegin);
   pContext->m_stack.Push(n);

   return 1;
  }
 }

 while(n > 0)
 {
  pContext->m_stack.Pop(nbegin);

  while( CRepeatElxT <x> :: m_pelx->MatchNext(pContext) )
  {
   if(pContext->m_nCurrentPos != nbegin)
   {
    pContext->m_stack.Push(nbegin);
    pContext->m_stack.Push(n);

    return 1;
   }
  }

  n --;
 }

 return 0;
}

// repeatx.cpp: implementation of the CRepeatElx class.
//
template <int x> CRepeatElxT <x> :: CRepeatElxT(ElxInterface * pelx, int ntimes)
{
 m_pelx   = pelx;
 m_nfixed = ntimes;
}

template <int x> int CRepeatElxT <x> :: Match(CContext * pContext) const
{
 return MatchFixed(pContext);
}

template <int x> int CRepeatElxT <x> :: MatchNext(CContext * pContext) const
{
 return MatchNextFixed(pContext);
}

template <int x> int CRepeatElxT <x> :: MatchFixed(CContext * pContext) const
{
 if(m_nfixed == 0)
  return 1;

 int n = 0;

 while(n < m_nfixed)
 {
  if(m_pelx->Match(pContext))
  {
   n ++;
  }
  else
  {
   n --;

   while(n >= 0 && ! m_pelx->MatchNext(pContext))
    n --;

   if(n >= 0)
    n ++;
   else
    return 0;
  }
 }

 return 1;
}

template <int x> int CRepeatElxT <x> :: MatchNextFixed(CContext * pContext) const
{
 if(m_nfixed == 0)
  return 0;

 // from last
 int n = m_nfixed - 1;

 while(n >= 0 && ! m_pelx->MatchNext(pContext))
  n --;

 if(n >= 0)
  n ++;
 else
  return 0;

 // match rest
 while(n < m_nfixed)
 {
  if(m_pelx->Match(pContext))
  {
   n ++;
  }
  else
  {
   n --;

   while(n >= 0 && ! m_pelx->MatchNext(pContext))
    n --;

   if(n >= 0)
    n ++;
   else
    return 0;
  }
 }

 return 1;
}

// Regexp
typedef CRegexpT <char> CRegexpA;
typedef CRegexpT <unsigned short> CRegexpW;

#if defined(_UNICODE) || defined(UNICODE)
 typedef CRegexpW CRegexp;
#else
 typedef CRegexpA CRegexp;
#endif

#endif//__DEELX_REGEXP__H__

 

使用方法很简单,只要包含这个文件,然后使用下面的

 

int test_all_num(const char* szCh)
{
 static CRegexpT<char> regexp("//d+");    //声明
 MatchResult result = regexp.MatchExact(szCh);  //测试
 return result.IsMatched();
}

 

添加一个按钮然后调用就可以了

void CRegexpDlg::OnBtnNum()
{
 // TODO: Add your control notification handler code here
 CString str = "asdasdasd";
 int i;
 i = test_all_num(szCh);
 if (i)
 {
  MessageBox("输入的是数字!");
 }
 else
 {
  MessageBox("输入的不是数字!");
 }
}

 

是不是很方便呢。欢迎使用。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值