简单的通配符匹配函数






4.83/5 (17投票s)
简单的通配符匹配函数
引言
使用 ? 和 * 进行简单的通配符匹配是我们日常工作中经常会做的事情,比如在打开命令提示符并使用 DIR 和 DEL 命令时。
但是如何在你的程序中正确地实现这个功能呢?
当然,你可以使用正则表达式,如果你的代码中已经使用了大量的 Boost、tr1 或 STL 组件,我推荐这样做。 但有时候,我喜欢简单易懂,避免在后台使用大量的库代码。 而且由于我看到很多错误且复杂的查询代码,所以我在这里提供这个小算法。
背景
这个通配符匹配函数的工作方式与你从 CMD.EXE DIR 命令中预期的完全一样。
Using the Code
该函数将要检查的字符串作为第一个参数,将包含或不包含任何通配符的掩码作为第二个参数。
如果字符串匹配,则返回 true
,如果不匹配,则返回 false
。 它并不特别复杂。
字符 ? 和 * 被视为通配符。
? 字符匹配正好一个字符,并且不匹配空字符串。
* 字符匹配任何字符序列,也匹配空字符串。
其他字符进行不区分大小写的比较。 我使用 CharUpper
并将它们转换为大写来执行此任务。 随意使用你自己的方法。
因为 * 匹配任何字符序列和空字符串,所以 WildcardMatch(_T(""),_T("*"))
返回 true
。
该函数本身和文档都很简单直观。
//////////////////////////////////////////////////////////////////////////
// WildcardMatch
// pszString - Input string to match
// pszMatch - Match mask that may contain wildcards like ? and *
//
// A ? sign matches any character, except an empty string.
// A * sign matches any string inclusive an empty string.
// Characters are compared caseless.
bool WildcardMatch(const TCHAR *pszString, const TCHAR *pszMatch)
{
// We have a special case where string is empty ("") and the mask is "*".
// We need to handle this too. So we can't test on !*pszString here.
// The loop breaks when the match string is exhausted.
while (*pszMatch)
{
// Single wildcard character
if (*pszMatch==_T('?'))
{
// Matches any character except empty string
if (!*pszString)
return false;
// OK next
++pszString;
++pszMatch;
}
else if (*pszMatch==_T('*'))
{
// Need to do some tricks.
// 1. The wildcard * is ignored.
// So just an empty string matches. This is done by recursion.
// Because we eat one character from the match string, the
// recursion will stop.
if (WildcardMatch(pszString,pszMatch+1))
// we have a match and the * replaces no other character
return true;
// 2. Chance we eat the next character and try it again, with a
// wildcard * match. This is done by recursion. Because we eat
// one character from the string, the recursion will stop.
if (*pszString && WildcardMatch(pszString+1,pszMatch))
return true;
// Nothing worked with this wildcard.
return false;
}
else
{
// Standard compare of 2 chars. Note that *pszSring might be 0
// here, but then we never get a match on *pszMask that has always
// a value while inside this loop.
if (::CharUpper(MAKEINTRESOURCE(MAKELONG(*pszString++,0)))
!=::CharUpper(MAKEINTRESOURCE(MAKELONG(*pszMatch++,0))))
return false;
}
}
// Have a match? Only if both are at the end...
return !*pszString && !*pszMatch;
}
历史
- 2011 年 4 月 28 日 -- 版本 1.0