// OXRegExpression.cpp: implementation of the COXRegExpression class. // ////////////////////////////////////////////////////////////////////// // Version: 9.3 #include "stdafx.h" #include "OXRegExpression.h" #include "OXMainRes.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif ////////////////////////////////////////////////////////////////////// // IMPLEMENT_SERIAL(COXRegExpression,CObject,OX_REGEXP_VERSION) //destructor - do cleanup on destroy COXRegExpression::~COXRegExpression() { RemoveAll(); } COXRegExpression::COXRegExpression(const COXRegExpression& regExpression) { ASSERT_VALID(®Expression); *this=regExpression; } const COXRegExpression& COXRegExpression::operator=(const COXRegExpression& regExpression) { ASSERT_VALID(®Expression); RemoveAll(); for (int n=0; nnType, ®Expression.GetTag(n)->sValue, regExpression.GetTag(n)->nMin, regExpression.GetTag(n)->nMax); m_sRule=regExpression.m_sRule; m_nNumber=regExpression.m_nNumber; m_nError=regExpression.m_nError; m_sSpace=regExpression.m_sSpace; m_sText=regExpression.m_sText; m_nFound=regExpression.m_nFound; ASSERT_VALID(this); return *this; } //adds tag to the list void COXRegExpression::AddTag(int nType, CString* pValue, int nFirst, int nSecond) { tRegExpTag* pRegtag=new tRegExpTag; pRegtag->nType=nType; pRegtag->nMin=nFirst; pRegtag->nMax=nSecond; if (pValue) pRegtag->sValue=*pValue; m_arTags.Add(pRegtag); } //this function do half a job - //parses rule you've supplied and //calls AddTag every time, new tag has been parsed. //Well, the rule can start from any character BOOL COXRegExpression::Parse(CString& sString, int* pnNumber/*=NULL*/) { int nType = OX_REGEXP_TAG_COMMON_CHAR; CString sValue; CString sNumber; int nNumber=0; if (!pnNumber) pnNumber=&nNumber; int nMin=0; int nMax=0; if (sString.IsEmpty() || sString.GetLength()<=*pnNumber) return FALSE; //main loop while (sString.GetLength()>*pnNumber) { TCHAR ch=sString.GetAt(*pnNumber); (*pnNumber)++; switch (nType) { case OX_REGEXP_TAG_COMMON_CHAR: switch (ch) { case TEXT('\\'): { int nRet=GetSpecialChar(sString, pnNumber, &ch); if (!nRet) { (*pnNumber)--; return FALSE; } if (nRet==OX_REGEXP_TAG_REFERENCE_BACK) { CString sPattern; int nNumber=(int) ch; if (GetPattern(nNumber, sPattern)) sValue+=sPattern; else { (*pnNumber)--; SetError(OX_REGEXP_ERROR_NO_REFERENCE); return FALSE; } continue; } if (nRet==OX_REGEXP_TAG_COMMON_CHAR) { sValue+=ch; continue; } if (!sValue.IsEmpty()) AddTag(OX_REGEXP_TAG_COMMON_CHAR,&sValue); switch (nRet) { case OX_REGEXP_TAG_DIGIT: case OX_REGEXP_TAG_NON_DIGIT: case OX_REGEXP_TAG_WHITESPACE: case OX_REGEXP_TAG_NON_WHITESPACE: case OX_REGEXP_TAG_ANY_WORD: case OX_REGEXP_TAG_ANY_NON_WORD: nType=nRet; sValue=""; continue; default: AddTag(nRet, NULL); sValue=""; continue; } } break; case TEXT('^'): if (!sValue.IsEmpty()) AddTag(OX_REGEXP_TAG_COMMON_CHAR,&sValue); AddTag(OX_REGEXP_TAG_BEGINING_OF_THE_LINE,NULL); sValue=""; break; case TEXT('$'): if (!sValue.IsEmpty()) AddTag(OX_REGEXP_TAG_COMMON_CHAR,&sValue); AddTag(OX_REGEXP_TAG_END_OF_THE_LINE,NULL); sValue=""; break; case TEXT('*'): case TEXT('?'): case TEXT('+'): if (sValue.IsEmpty()) { (*pnNumber)--; SetError(OX_REGEXP_ERROR_MUST_CHAR_BEFORE); return FALSE; } switch(ch) { case TEXT('*'): //nType=OX_REGEXP_TAG_CHAR_ZERO_OR_MORE; nMin=0; nMax=-1; break; case TEXT('+'): //nType=OX_REGEXP_TAG_CHAR_ONE_OR_MORE; nMin=1; nMax=-1; break; case TEXT('?'): //nType=OX_REGEXP_TAG_CHAR_ZERO_OR_ONE; nMin=0; nMax=1; break; } ch=sValue.GetAt(sValue.GetLength()-1); sValue=(sValue.GetLength()==1)? _T(""):sValue.Left(sValue.GetLength()-1); if (!sValue.IsEmpty()) { AddTag(OX_REGEXP_TAG_COMMON_CHAR,&sValue); } sValue=ch; AddTag(OX_REGEXP_TAG_COMMON_CHAR,&sValue, nMin, nMax); sValue=""; nType=OX_REGEXP_TAG_COMMON_CHAR; break; case TEXT('.'): if (!sValue.IsEmpty()) { AddTag(OX_REGEXP_TAG_COMMON_CHAR,&sValue); } nType=OX_REGEXP_TAG_CHAR_NOT_NEW_LINE; sValue=""; break; case TEXT('('): if (!sValue.IsEmpty()) { AddTag(OX_REGEXP_TAG_COMMON_CHAR,&sValue); } sValue=""; nType=OX_REGEXP_TAG_PATTERN; break; case TEXT(')'): case TEXT(']'): case TEXT('}'): { (*pnNumber)--; SetError(OX_REGEXP_ERROR_UNEXPECTED_SPECCHAR); return FALSE; } case TEXT('|'): if (sValue.IsEmpty()) { (*pnNumber)--; SetError(OX_REGEXP_ERROR_MUST_CHAR_BEFORE); return FALSE; } ch=sValue.GetAt(sValue.GetLength()-1); sValue=(sValue.IsEmpty())?_T(""):sValue.Left( sValue.GetLength()-1); if (!sValue.IsEmpty()) AddTag(OX_REGEXP_TAG_COMMON_CHAR,&sValue); sValue=ch; nType=OX_REGEXP_TAG_CHARS_EITHER; break; case TEXT('{'): { if (sValue.IsEmpty()) { (*pnNumber)--; SetError(OX_REGEXP_ERROR_MUST_CHAR_BEFORE); return FALSE; } ch=sValue.GetAt(sValue.GetLength()-1); sValue=(sValue.IsEmpty())?_T(""):sValue.Left( sValue.GetLength()-1); if (!sValue.IsEmpty()) AddTag(OX_REGEXP_TAG_COMMON_CHAR,&sValue); sValue=ch; int nMin, nMax; int nRet=GetMinMaxCount(sString, pnNumber, &nMin, &nMax); if (!nRet) { (*pnNumber)--; return FALSE; } if (nRet==OX_REGEXP_TAG_CHARS_EXACTLY) { if (nMin) { for (int n=1;n*pnNumber && sString.GetAt(*pnNumber)==TEXT('|')) { bContinue=TRUE; (*pnNumber)++; } else bContinue=FALSE; }while(sString.GetLength()>*pnNumber && bContinue); if (bContinue) { (*pnNumber)--; SetError(OX_REGEXP_ERROR_UNEXPECTED_END_EITHER); return FALSE; } AddTag(OX_REGEXP_TAG_CHARSET, &sValue); sValue=""; nType=OX_REGEXP_TAG_COMMON_CHAR; } break; case OX_REGEXP_TAG_CHARSET: if (ch==TEXT('^') && sValue.IsEmpty()) { nType=OX_REGEXP_TAG_NON_CHARSET; continue; } case OX_REGEXP_TAG_NON_CHARSET: case OX_REGEXP_TAG_PATTERN: case OX_REGEXP_TAG_CHARSET_BEGIN_LINE: case OX_REGEXP_TAG_NON_CHARSET_BEGIN_LINE: case OX_REGEXP_TAG_CHARSET_END_LINE: case OX_REGEXP_TAG_NON_CHARSET_END_LINE: case OX_REGEXP_TAG_CHARSET_BEGIN_END_LINE: case OX_REGEXP_TAG_NON_CHARSET_BEGIN_END_LINE: switch (ch) { case TEXT('^'): if (nType==OX_REGEXP_TAG_PATTERN) { (*pnNumber)--; SetError(OX_REGEXP_ERROR_UNEXPECTED_SPECCHAR); return FALSE; } switch (nType) { case OX_REGEXP_TAG_NON_CHARSET: nType=OX_REGEXP_TAG_NON_CHARSET_BEGIN_LINE; break; case OX_REGEXP_TAG_CHARSET_END_LINE: nType=OX_REGEXP_TAG_CHARSET_BEGIN_END_LINE; break; case OX_REGEXP_TAG_CHARSET: nType=OX_REGEXP_TAG_CHARSET_BEGIN_LINE; break; case OX_REGEXP_TAG_NON_CHARSET_END_LINE: nType=OX_REGEXP_TAG_NON_CHARSET_BEGIN_END_LINE; break; case OX_REGEXP_TAG_CHARSET_BEGIN_LINE: case OX_REGEXP_TAG_NON_CHARSET_BEGIN_LINE: case OX_REGEXP_TAG_CHARSET_BEGIN_END_LINE: case OX_REGEXP_TAG_NON_CHARSET_BEGIN_END_LINE: break; default: ASSERT(FALSE); break; } break; case TEXT('$'): if (nType==OX_REGEXP_TAG_PATTERN) { (*pnNumber)--; SetError(OX_REGEXP_ERROR_UNEXPECTED_SPECCHAR); return FALSE; } switch (nType) { case OX_REGEXP_TAG_NON_CHARSET: nType=OX_REGEXP_TAG_NON_CHARSET_END_LINE; break; case OX_REGEXP_TAG_CHARSET_BEGIN_LINE: nType=OX_REGEXP_TAG_CHARSET_BEGIN_END_LINE; break; case OX_REGEXP_TAG_CHARSET: nType=OX_REGEXP_TAG_CHARSET_END_LINE; break; case OX_REGEXP_TAG_NON_CHARSET_BEGIN_LINE: nType=OX_REGEXP_TAG_NON_CHARSET_BEGIN_END_LINE; break; case OX_REGEXP_TAG_CHARSET_END_LINE: case OX_REGEXP_TAG_NON_CHARSET_END_LINE: case OX_REGEXP_TAG_CHARSET_BEGIN_END_LINE: case OX_REGEXP_TAG_NON_CHARSET_BEGIN_END_LINE: break; default: ASSERT(FALSE); break; } break; case TEXT('*'): case TEXT('+'): case TEXT('?'): case TEXT('.'): case TEXT('('): case TEXT('|'): case TEXT('}'): case TEXT('['): { (*pnNumber)--; SetError(OX_REGEXP_ERROR_UNEXPECTED_SPECCHAR); return FALSE; } case TEXT(']'): if (nType!=OX_REGEXP_TAG_PATTERN) { AddTag(nType,&sValue); sValue=""; nType=OX_REGEXP_TAG_COMMON_CHAR; break; } else { (*pnNumber)--; SetError(OX_REGEXP_ERROR_UNEXPECTED_SPECCHAR); return FALSE; } case TEXT('\\'): { int nRet=GetSpecialChar(sString, pnNumber,&ch); if (nRet!=OX_REGEXP_TAG_COMMON_CHAR) { if (nRet) SetError(OX_REGEXP_ERROR_UNEXPECTED_SPECCHAR); (*pnNumber)--; return FALSE; } if (nType==OX_REGEXP_TAG_PATTERN) sValue+=ch; else if (sValue.Find(ch)==-1) sValue+=ch; } break; case TEXT('/'): if (!GetAsciiChar(sString, pnNumber, &ch)) { (*pnNumber)--; return FALSE; } if (nType==OX_REGEXP_TAG_PATTERN) sValue+=ch; else if (sValue.Find(ch)==-1) sValue+=ch; break; case TEXT('{'): { if (sValue.IsEmpty()) { (*pnNumber)--; SetError(OX_REGEXP_ERROR_MUST_CHAR_BEFORE); return FALSE; } int nMin,nMax; int nRet=GetMinMaxCount(sString, pnNumber, &nMin, &nMax); if (nRet!=OX_REGEXP_TAG_CHARS_EXACTLY) { if (nRet) SetError(OX_REGEXP_ERROR_UNEXPECTED_MATCH); (*pnNumber)--; return FALSE; } if (nType==OX_REGEXP_TAG_PATTERN) { for (int n=1;nCHAR_NINE) { SetError(OX_REGEXP_ERROR_UNEXPECTED_SPECCHAR); return FALSE; } else { CString sTemp(ch); *pch=(TCHAR) _ttoi((LPCTSTR) sTemp); return OX_REGEXP_TAG_REFERENCE_BACK; } break; } } //called by Parse when found '/' char that //means ASCII code found BOOL COXRegExpression::GetAsciiChar(CString& sString, int* pnNumber, LPTSTR pch) { *pch=NULL; CString sNumber; int nNumber=0; if (sString.GetLength()<=*pnNumber) { SetError(OX_REGEXP_ERROR_UNEXPECTED_END_ASCII); return FALSE; } while (sString.GetLength()>*pnNumber) { TCHAR ch=sString.GetAt(*pnNumber); (*pnNumber)++; if (ch==TEXT('/')) { if (sNumber.IsEmpty()) { SetError(OX_REGEXP_ERROR_EMPTY_PARENTHESES_ASCII); return FALSE; } else { ASSERT(nNumber>=0 && nNumber<256); *pch=(TCHAR) nNumber; return TRUE; } } else if (sNumber.GetLength()>=3) { SetError(OX_REGEXP_ERROR_WRONG_ASCII_NUMBER); return FALSE; } else if (chCHAR_NINE) { SetError(OX_REGEXP_ERROR_MUST_DIGIT); return FALSE; } else { sNumber+=ch; nNumber=_ttoi((LPCTSTR) sNumber); if (nNumber<0 || nNumber>255) { SetError(OX_REGEXP_ERROR_WRONG_ASCII_NUMBER); return FALSE; } } } SetError(OX_REGEXP_ERROR_NO_LAST_PARENTHES_ASCII); return FALSE; } //called by Parse when //encounters '{' character that means //number of the preceding character found int COXRegExpression::GetMinMaxCount(CString& sString, int* pnNumber, int* pMin, int* pMax) { *pMin=-1; *pMax=-1; CString sNumber; int nComma=0; BOOL bAtLeast=FALSE; while(sString.GetLength()>*pnNumber) { TCHAR ch=sString.GetAt(*pnNumber); (*pnNumber)++; if (ch==TEXT('}')) { if (!bAtLeast) { if (sNumber.IsEmpty()) { SetError(OX_REGEXP_ERROR_EMPTY_PARENTHESES); return FALSE; } *pMin=_ttoi((LPCTSTR) sNumber); return OX_REGEXP_TAG_CHARS_EXACTLY; } else if (sNumber.IsEmpty()) return OX_REGEXP_TAG_CHARS_AT_LEAST; else { *pMax=_ttoi((LPCTSTR) sNumber); if (*pMax>*pMin) return OX_REGEXP_TAG_CHARS_AT_LEAST_MOST; else { *pnNumber=nComma; (*pnNumber)++; SetError(OX_REGEXP_ERROR_INVALID_MOSTLEAST); return FALSE; } } } else if (ch==TEXT(',')) { if (bAtLeast) { SetError(OX_REGEXP_ERROR_TOO_MANY_COMMAS); return FALSE; } *pMin=sNumber.IsEmpty()?NULL:_ttoi((LPCTSTR) sNumber); sNumber=""; bAtLeast=TRUE; nComma=*pnNumber; } else if (chCHAR_NINE) { SetError(OX_REGEXP_ERROR_MUST_DIGIT); return FALSE; } else { sNumber+=ch; } } SetError(OX_REGEXP_ERROR_NO_LAST_PARENTHES); return FALSE; } //public function //call this function to load rule for parse BOOL COXRegExpression::LoadRule(CString sRule, int* pnNumber) { while (m_arTags.GetSize()) { delete (tRegExpTag*) m_arTags.GetAt(0); m_arTags.RemoveAt(0); } m_arTags.RemoveAll(); m_nError=NULL; BOOL bRet=Parse(sRule, pnNumber); if (bRet) m_sRule=sRule; else RemoveAll(); return bRet; } //public function //call this function to load rule BOOL COXRegExpression::LoadRule(LPCTSTR lpszRule, int* pnNumber) { CString sRule=lpszRule; return LoadRule(sRule, pnNumber); } //this function translates error number to string void COXRegExpression::TranslateError(int nError, CString& sError) { switch (nError) { case OX_REGEXP_ERROR_MUST_CHAR_BEFORE: VERIFY(sError.LoadString(IDS_OX_REGEXPMUSTCHARBEFORE));//"Must preceed character before." break; case OX_REGEXP_ERROR_UNEXPECTED_SPECCHAR: VERIFY(sError.LoadString(IDS_OX_REGEXPUNEXPSPECCHAR));//"Unexpected special char has been found." break; case OX_REGEXP_ERROR_UNEXPECTED_MATCH: VERIFY(sError.LoadString(IDS_OX_REGEXPNOTALLOWEDSEQ));//"Not allowed sequence has been found" break; case OX_REGEXP_ERROR_UNEXPECTED_END_EITHER: VERIFY(sError.LoadString(IDS_OX_REGEXPMUSTFOLLOWBYCHAR));//"Must follow by character." break; case OX_REGEXP_ERROR_UNEXPECTED_END_SPECCHAR: VERIFY(sError.LoadString(IDS_OX_REGEXPUNEXPENDOFSTR));//"Unexpected end of string has been reached." break; case OX_REGEXP_ERROR_MUST_DIGIT: VERIFY(sError.LoadString(IDS_OX_REGEXPONLYDIGIT));//"Only digit allowed." break; case OX_REGEXP_ERROR_UNEXPECTED_END_ASCII: VERIFY(sError.LoadString(IDS_OX_REGEXPUNEXPASCIIEND));//"Unexpected end of the ASCII sequence." break; case OX_REGEXP_ERROR_EMPTY_PARENTHESES_ASCII: VERIFY(sError.LoadString(IDS_OX_REGEXPNOASCII));//"No ASCII value." break; case OX_REGEXP_ERROR_WRONG_ASCII_NUMBER: VERIFY(sError.LoadString(IDS_OX_REGEXPINVALIDASCIINUMBER));//"Invalid ASCII number." break; case OX_REGEXP_ERROR_NO_LAST_PARENTHES_ASCII: VERIFY(sError.LoadString(IDS_OX_REGEXPNOENDSPLASH));//"No ending slash has been found while processing ASCII value." break; case OX_REGEXP_ERROR_EMPTY_PARENTHESES: VERIFY(sError.LoadString(IDS_OX_REGEXPNOVALUESINPARENTHS));//"No values between parentheses." break; case OX_REGEXP_ERROR_TOO_MANY_COMMAS: VERIFY(sError.LoadString(IDS_OX_REGEXPTOOMANYCOMMAS));//"Too many commas in the sequence. Only one allowed." break; case OX_REGEXP_ERROR_NO_LAST_PARENTHES: VERIFY(sError.LoadString(IDS_OX_REGEXPNOCLOSEPARENTH));//"No closing parentheses has been found." break; case OX_REGEXP_ERROR_UNEXPECTED_END_OF_STRING: VERIFY(sError.LoadString(IDS_OX_REGEXPUNEXPSTRINGEND));//"Unexpected end of string." break; case OX_REGEXP_ERROR_INVALID_MOSTLEAST: VERIFY(sError.LoadString(IDS_OX_REGEXPSECONDGREATER));//"Second value must be greater first one." break; case OX_REGEXP_ERROR_NO_REFERENCE: VERIFY(sError.LoadString(IDS_OX_REGEXPNOSUCHREFRENS));//"No such back reference." break; default: VERIFY(sError.LoadString(IDS_OX_REGEXPUNKNOWNERROR));//"Unknown error" } } //retrieve string (pattern) by number //called by Parse when '\0'-'\9' found BOOL COXRegExpression::GetPattern(int nNumber, CString &sPattern) { if (nNumber<0 ||nNumber>9) return FALSE; int nIndex=0; for (int n=0;nnType==OX_REGEXP_TAG_PATTERN) { if (nIndex==nNumber) { sPattern=pTag->sValue; return TRUE; } else nIndex++; } } return FALSE; } //call this function to match your text //to the rule you've loaded before int COXRegExpression::Match(CString &sString) { if (sString.IsEmpty() || !GetTagCount()) return NULL; m_sText=sString; int nSuccess=0; m_nFound=0; for (m_nNumber=0;m_nNumbernMin; int nMax=(pTag->nMax==-1)? (sString.GetLength()-1-*pNumber):pTag->nMax; if (!nMin) { if (nTag=0); m_nFound++; if (!OnMatch(m_nNumber, (*pNumber)-m_nNumber)) return OX_REGEXP_CANCELED; nSuccess=TRUE; } } switch (pTag->nType) { case OX_REGEXP_TAG_COMMON_CHAR: case OX_REGEXP_TAG_PATTERN: ASSERT(!pTag->sValue.IsEmpty()); case OX_REGEXP_TAG_CHARS_AT_LEAST_MOST: case OX_REGEXP_TAG_CHARS_AT_LEAST: { for (int n=0;nsValue)!=NULL) { return nSuccess; } else { *pNumber+=pTag->sValue.GetLength(); if (n+1>=nMin) { if (nTag=0); m_nFound++; if (!OnMatch(m_nNumber, (*pNumber)-m_nNumber)) return OX_REGEXP_CANCELED; nSuccess=TRUE; } } } } return nSuccess; } break; case OX_REGEXP_TAG_BEGINING_OF_THE_LINE: { for (int n=0;n=0); m_nFound++; if (!OnMatch(m_nNumber, (*pNumber)-m_nNumber)) return OX_REGEXP_CANCELED; } else { nSuccess |=MatchNextTag(sString,nTag+1,pNumber); if (nSuccess & OX_REGEXP_CANCELED) return OX_REGEXP_CANCELED; } } return nSuccess; } case OX_REGEXP_TAG_END_OF_THE_LINE: { for (int n=0;nsString.GetLength()) return FALSE; if (*pNumber==sString.GetLength() || ((sString.GetLength()- *pNumber-1) && (sString.GetAt(*pNumber+1)==TEXT('\n')))) { (*pNumber)++; if (nTag==GetTagCount()-1) { ASSERT((*pNumber)-m_nNumber>=0); m_nFound++; if (!OnMatch(m_nNumber, (*pNumber)-m_nNumber)) return OX_REGEXP_CANCELED; nSuccess=TRUE; } else { nSuccess |=MatchNextTag(sString,nTag+1,pNumber); if (nSuccess & OX_REGEXP_CANCELED) return OX_REGEXP_CANCELED; } } else return nSuccess; } } break; case OX_REGEXP_TAG_CHAR_NOT_NEW_LINE: { for (int n=0;n=nMin) { if (nTag=0); m_nFound++; if (!OnMatch(m_nNumber, (*pNumber)-m_nNumber)) return OX_REGEXP_CANCELED; nSuccess=TRUE; } } } } return nSuccess; } break; case OX_REGEXP_TAG_CHARSET: { for (int n=0;nsValue.Find(sString.GetAt(*pNumber))==-1) { return nSuccess; } else { (*pNumber)++; if (n+1>=nMin) { if (nTag=0); m_nFound++; if (!OnMatch(m_nNumber, (*pNumber)-m_nNumber)) return OX_REGEXP_CANCELED; nSuccess=TRUE; } } } } return nSuccess; } break; case OX_REGEXP_TAG_NON_CHARSET: { for (int n=0;nsValue.Find(sString.GetAt(*pNumber))!=-1) { return nSuccess; } (*pNumber)++; if (n+1>=nMin) { if (nTag=0); m_nFound++; if (!OnMatch(m_nNumber, (*pNumber)-m_nNumber)) return OX_REGEXP_CANCELED; nSuccess=TRUE; } } } return nSuccess; } break; case OX_REGEXP_TAG_WORD_BOUNDARY: ASSERT(nMin==1 && nMax==1);//only one tag allowed if (*pNumber>=sString.GetLength()) return FALSE; if ((*pNumber && (((m_sSpace.Find(sString.GetAt(*pNumber)))==-1) ^ ((m_sSpace.Find(sString.GetAt(*pNumber-1)))==-1))) || (!*pNumber && (m_sSpace.Find(sString.GetAt(*pNumber)))==-1 )) { if (nTag==GetTagCount()-1) { ASSERT((*pNumber)-m_nNumber>=0); m_nFound++; if (!OnMatch(m_nNumber, (*pNumber)-m_nNumber)) return OX_REGEXP_CANCELED; return TRUE; } else return MatchNextTag(sString, nTag+1, pNumber); } else return nSuccess; break; case OX_REGEXP_TAG_NON_WORD_BOUNDARY: ASSERT(nMin==1 && nMax==1);//only one tag allowed if (*pNumber>=sString.GetLength()) return FALSE; if ((*pNumber && !(((m_sSpace.Find(sString.GetAt(*pNumber)))==-1) ^ ((m_sSpace.Find(sString.GetAt(*pNumber-1)))==-1))) || (!*pNumber && (m_sSpace.Find(sString.GetAt(*pNumber)))!=-1 )) { if (nTag==GetTagCount()-1) { ASSERT((*pNumber)-m_nNumber>=0); m_nFound++; if (!OnMatch(m_nNumber, (*pNumber)-m_nNumber)) return OX_REGEXP_CANCELED; return TRUE; } else return MatchNextTag(sString, nTag+1, pNumber); } else return nSuccess; break; case OX_REGEXP_TAG_DIGIT: { for (int n=0; nTEXT('9')) return nSuccess; else { (*pNumber)++; if (n+1>=nMin) { if (nTag=0); m_nFound++; if (!OnMatch(m_nNumber, (*pNumber)-m_nNumber)) return OX_REGEXP_CANCELED; nSuccess=TRUE; } } } } return nSuccess; } break; case OX_REGEXP_TAG_NON_DIGIT: { for (int n=0; n=TEXT('0') && sString.GetAt(*pNumber)<=TEXT('9')) { return nSuccess; } else { (*pNumber)++; if (n+1>=nMin) { if (nTag=0); m_nFound++; if (!OnMatch(m_nNumber, (*pNumber)-m_nNumber)) return OX_REGEXP_CANCELED; nSuccess=TRUE; } } } } return nSuccess; } break; case OX_REGEXP_TAG_WHITESPACE: { for (int n=0; n=nMin) { if (nTag=0); m_nFound++; if (!OnMatch(m_nNumber, (*pNumber)-m_nNumber)) return OX_REGEXP_CANCELED; nSuccess=TRUE; } } } } return nSuccess; } break; case OX_REGEXP_TAG_NON_WHITESPACE: { for (int n=0; n=nMin) { if (nTag=0); m_nFound++; if (!OnMatch(m_nNumber, (*pNumber)-m_nNumber)) return OX_REGEXP_CANCELED; nSuccess=TRUE; } } } } return nSuccess; } break; case OX_REGEXP_TAG_ANY_WORD: { if (sString.GetLength()<=*pNumber) return FALSE; for (int n=0; n=TEXT('a') && ch<=TEXT('z')) || (ch>=TEXT('A') && ch<=TEXT('Z')) || (ch>=TEXT('0') && ch<=TEXT('9')) || ch==TEXT('_')))) { return nSuccess; } else { (*pNumber)++; if (n+1>=nMin) { if (nTag=0); m_nFound++; if (!OnMatch(m_nNumber, (*pNumber)-m_nNumber)) return OX_REGEXP_CANCELED; nSuccess=TRUE; } } } } return nSuccess; } break; case OX_REGEXP_TAG_ANY_NON_WORD: { for (int n=0; n=TEXT('a') && ch<=TEXT('z')) || (ch>=TEXT('A') && ch<=TEXT('Z')) || (ch>=TEXT('0') && ch<=TEXT('9')) || ch==TEXT('_')) { return nSuccess; } else { (*pNumber)++; if (n+1>=nMin) { if (nTag=0); m_nFound++; if (!OnMatch(m_nNumber, (*pNumber)-m_nNumber)) return OX_REGEXP_CANCELED; nSuccess=TRUE; } } } } return nSuccess; } break; default: ASSERT(FALSE);//unexpected type } return nSuccess; } //this virtual function do nothing. //it will be called every time matching substring has been found //override this function to retrieve data BOOL COXRegExpression::OnMatch(int nStart, int nLength) { UNREFERENCED_PARAMETER(nStart); UNREFERENCED_PARAMETER(nLength); return TRUE; }