Introduction
This article was inspired by Jack Handy (Wildcard string compare).
It describes a function to compare strings with wildcards. I have modified Jack's function to use MFC and use optional character in the wildcard string.
Wildcard sample
If you want to check a string like 'test' or 'tet', you may use the wildcard like this : te^st where ^ indicates an optional char.
I included another parameter to limit characters used in wildcard * or ?.
if (WildMatch("^-*?^.*", sValue, "0123456789")) {
MessageBox("OK you have a real");
} else {
MessageBox("Not a real");
}
This sample validates the string in sValue
has a good format to be a real number.
Function code
BOOL WildMatch(CString sWild, CString sString, CString sLimitChar)
{
BOOL bAny = FALSE;
BOOL bNextIsOptional = FALSE;
BOOL bAutorizedChar = TRUE;
int i=0;
int j=0;
while (i<sString.GetLength())
{
if (j<sWild.GetLength())
{
if (sWild[j]=='*')
{
j++;
if (j>=sWild.GetLength())
{
while (!sLimitChar.IsEmpty() && i<sString.GetLength())
{
if (sLimitChar.Find(sString[i])<0)
return FALSE;
i++;
}
return TRUE;
}
bAny = TRUE;
bNextIsOptional = FALSE;
}
else
{
if (sWild[j]=='^')
{
j++;
bNextIsOptional = TRUE;
}
else
{
bAutorizedChar =
((sLimitChar.IsEmpty()) || (sLimitChar.Find(sString[i])>=0));
if (
sWild[j] == sString[i]
|| (sWild[j] == '?' && bAutorizedChar)
|| (bNextIsOptional && !(bAny && bAutorizedChar)))
{
if (sWild[j] == sString[i])
bAny = FALSE;
if (sWild[j] == sString[i] || sWild[j] == '?')
i++;
j++;
bNextIsOptional = FALSE;
}
else
if (bAny && bAutorizedChar)
i++;
else
return FALSE;
}
}
}
else
return FALSE;
}
if (j<sWild.GetLength() && sWild[j]=='^')
{
bNextIsOptional = TRUE;
j++;
}
while ((j<sWild.GetLength() && sWild[j]=='*') || bNextIsOptional)
{
j++;
bNextIsOptional = FALSE;
if (j<sWild.GetLength() && sWild[j]=='^')
{
bNextIsOptional = TRUE;
j++;
}
}
return j>=sWild.GetLength();
}
CEdit input validation
This sample shows you how to use this function to control input validation in a dynamic way.
Be careful when you define your wildcard, because it must be always true! If you want more advanced testing, don't test in real time but do only when the user validates.
For example, if you use ^-?*^.*, the user can never put the minus sign first, because '?' specifies one char is always necessary!
You can put this code in the OnChar
of your CEdit
child class, or if you don't want to derive a new class, you can put it in the PreTranslateMessage
of the mother window, like:
if (pMsg->message==WM_CHAR && pMsg->hwnd==pEdit->m_hWnd &&
pMsg->wParam>=32)
{
CString sSaveText="";
CString sNewText="";
CString sLimitChar="0123456789";
CString sWildCard="^-*^.*";
int iNbMaxChar = 10;
if (m_bMakeUpper)
pMsg->wParam = toupper(pMsg->wParam);
DWORD dwSaveSel = pEdit->GetSel();
pEdit->GetWindowText(sSaveText);
pEdit->SendMessage(WM_CHAR, pMsg->wParam, pMsg->lParam);
pEdit->GetWindowText(sNewText);
if (!WildMatch(m_sWildCard, sNewText, sLimitChar) ||
sNewText.GetLength()>iNbMaxChar)
{
pEdit->SetWindowText(sSaveText);
pEdit->SetSel(dwSaveSel);
}
}