Introduction
Regular expression provides a convenient way to specify complicated string
pattern for search, replace or validate the text input. Since it is very useful, many people wrote their own library. Many libraries I found are buggy and it takes a lot of time to debug source code. However, actually you do not need to search any more, since there is already one built in your computer for free – the regular expression parser written by Microsoft.
As many other utilities, Microsoft provides this functionality using COM interface. It is easy to find this COM server object, named Microsoft VBScript Regular Expressions 5.5, with the tool oleview:
One problem is that there is no type library associated with this DLL. Fortunately, it is not a big deal since we have the IDL definition. From OleView, save the IDL definition into a file and use MIDL to compile it, you will get type library. After that, we can use this type library within our C++ program. Suppose we have this file named RegExp.tlb.
Use Regular Expression
You can find all the documentation in either MSDN or the URL http://msdn.microsoft.com/scripting/default.htm?/scripting/vbscript/doc/vsobjregexp.htm. Though it is for scripting, you can still use them directly with the help of the newly-added keyword #import
since Visual C++ 6. Generally you define a pattern, then you can test this pattern against the input string
or execute to see whether there are any matches.
To demonstrate its usage, we wrote a custom DDX routine to verify the input of a control in a dialog. The function prototype is listed as follows:
void WINAPI DDX_RegExp(CDataExchange* pDX, int nIDC, LPCTSTR lpszPattern, CString& value);
If the control input exactly matches the specified pattern (lpszPattern
), the validation is passed, otherwise a message box will pop up.
#import "RegExp.tlb" no_namespace
...
void AFXAPI DDX_RegExp(CDataExchange* pDX, int nIDC, LPCTSTR lpszPattern, CString& value)
{
try {
static IRegExpPtr regExp( __uuidof(RegExp) );
regExp->Pattern = _bstr_t(lpszPattern);
HWND hWndCtrl = pDX->PrepareEditCtrl(nIDC);
if (pDX->m_bSaveAndValidate)
{
int nLen = ::GetWindowTextLength(hWndCtrl);
::GetWindowText(hWndCtrl, value.GetBufferSetLength(nLen),nLen+1);
value.ReleaseBuffer();
if ( regExp->Test( (LPCTSTR)value) )
{
IMatchCollectionPtr matches=regExp->Execute((LPCTSTR)value);
if ( matches->Count== 1)
{
IMatchPtr match = matches->Item[0];
if ( match->FirstIndex==0 && match->Length == value.GetLength() )
{
return;
}
}
}
CString strMsg = CString("The input does not exactly have the pattern ") +
lpszPattern;
pDX->m_pDlgWnd->MessageBox(strMsg);
pDX->PrepareEditCtrl(nIDC);
pDX->Fail();
}
else
{
}
}
catch (_com_error& e)
{
AfxMessageBox( e.ErrorMessage() );
}
}
In the code above, we first use Test
method to see whether there is a match. If there is one, we use Execute
method to retrieve all the matches. There should be only one match.
After we define that, we can use this function in our MFC application. Note that you must initialize the COM library first in your application. The following will validate an input box to see if it matches the phone number format:
DDX_RegExp(pDX, IDC_INPUT, _T("\\d{3}-\\d{3}-\\d{4}"), m_strInput);
In this way, you can write validation code for a more complicated pattern. The COM makes things a lot easier.
License
This article has no explicit license attached to it, but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below. A list of licenses authors might use can be found here.