含有通配符的字符串匹配算法

#define  SAFE_DELETE(p) if((p)){delete (p); (p) = NULL;}
#define  SAFE_DELETE_ARRAY(p) if((p)){delete [](p); (p) = NULL;}


/*
Sunday-字符串匹配算法--一种优于KMP的算法
思想类似于BM算法,只不过是从左向右匹配
遇到不匹配的看大串中匹配范围之外的右侧第一个字符在小串中的最右位置
另外:采用BM/KMP的预处理的做法,事先计算好移动步长,等到遇到不匹配的值直接使用
算法核心思想,从左向右匹配,遇到不匹配的看大串中匹配范围之外的右侧第一个字符在小串中的最右位置
根据事先计算好的移动步长移动大串指针,直到匹配
http://blog.csdn.net/WINCOL/article/details/4795369
*/


//功  能:在mainStr中查找字符串subStr,subStr中可以包含通配字符‘?’  
//参  数:nStart为在mainStr中的起始查找位置  
//返回值:成功返回匹配位置,否则返回-1  
int StringSearch(const char *mainStr, const char *subStr,int nStart = 0)
{
    int mainStrLen=strlen(mainStr);
    int subStrLen = strlen(subStr);
    if (subStrLen < 1 || nStart >= mainStrLen)
    {
        return -1;
    }
    if (nStart < 0)
    {
        nStart = 0;
    }
    /*设定每个字符最右移动步长,保存每个字符的移动步长
    如果大串中匹配字符的右侧一个字符没在子串中,大串移动步长=整个串的距离+1
    如果大串中匹配范围内的右侧一个字符在子串中,大串移动距离=子串长度-这个字符在子串中的位置
    */
    //一个字符8位 最大256种
    int charStep[256] = {0};
    int default_step = subStrLen;
    for ( int i = subStrLen-1;i >= 0;i--)
    {
        // 如果有通配符,则设置默认步长
        if(subStr[i] == '?' )
        {
            default_step = subStrLen - i;
            break;
        }
    }
   
    for( int i=0;i<256;i++)
        charStep[i] = default_step;
    //从左向右扫描一遍 保存子串中每个字符所需移动步长
    for( int i = 0;i < subStrLen; i++)
    {
        charStep[( unsigned char )subStr[i]] = subStrLen - i ;
    }
    
     int main_i = nStart;
     int sub_j = 0;
     while(main_i < mainStrLen)
     {                 
            //保存大串每次开始匹配的起始位置,便于移动指针
             int tem = main_i;
             while(sub_j < subStrLen)
             {
                    if(mainStr[main_i] ==   subStr[sub_j] || ( subStr[sub_j] == '?' && main_i < mainStrLen) )
                    {
                            main_i++;
                            sub_j++;
                            continue;                  
                    }               
                    else
                    {
                        //如果匹配范围外已经找不到右侧第一个字符,则匹配失败
                         if(tem + subStrLen > mainStrLen)
                                     return -1;
                         //否则 移动步长 重新匹配
                         char firstRightChar=mainStr[tem + subStrLen];
                         main_i=tem+charStep[( unsigned char)firstRightChar];
                         sub_j=0;  
                         break;//退出本次失败匹配 重新一轮匹配
                    } 
             }
             if(sub_j == subStrLen)
                       return main_i-subStrLen;
     }
     return -1;
}






//功   能:带通配符的字符串匹配  
//参   数:lpszSour是一个普通字符串;  
//            lpszMatch是一可以包含通配符的字符串;  
//            bMatchCase为false,不区分大小写,否则区分大小写。  
//返  回  值:匹配,返回1;否则返回0。  
//通配符意义:  
//      ‘*’ 代表任意字符串,包括空字符串;  
//      ‘?’ 代表任意一个字符,不能为空;  
bool MatchString(const char* lpszSour, const char * lpszMatch, bool bMatchCase = true )  
{  
    if(lpszSour == NULL || lpszMatch == NULL)  
        return false ;  


    if(lpszMatch[0] == 0) //Is a empty string  
    {  
        if(lpszSour[0] == 0)  
            return true ;  
        else  
            return false ;  
    }  


    //生成比较用临时源字符串'szSource'  
    size_t len_src = strlen(lpszSour);
    char* szSrc =  new char [ strlen(lpszSour)+1 ];  
   
    if (bMatchCase)
    {
        memmove(szSrc,lpszSour,len_src + 1 );
    }
    else
    {
        int i = 0;  
        while(lpszSour[i])  
        {  
            szSrc[i] = tolower(lpszSour[i]);
            i++;  
        }  
        szSrc[i] = 0;  
    }


    //生成比较用临时匹配字符串'szMatcher'  
    //把lpszMatch里面连续的“*”并成一个“*”后复制到szMatcher中  
    char* szMatcher = new char [strlen(lpszMatch) + 1]; 
    int len_match = 0;
    int i = 0;
    int wildcard_count = 0;
    while(lpszMatch[i])
    {
        szMatcher[len_match++] = bMatchCase? lpszMatch[i] : tolower(lpszMatch[i]);
        if(lpszMatch[i] == '*' )  
        {
            while(lpszMatch[++i] == '*' );  
            wildcard_count++;
        }
        else  
        {
            i++;  
        }
    }
    szMatcher[len_match] = 0;
    //如果匹配字符串只有‘*’则直接返回ture  
    if (len_match == 1 && szMatcher[0] == '*')
    {
        SAFE_DELETE_ARRAY(szSrc);
        SAFE_DELETE_ARRAY(szMatcher);
        return true ;
    }
   
    //如果没有包含通配符则直接匹配
    if (wildcard_count == 0)
    {
        if (len_match == len_src && StringSearch(szSrc, szMatcher) == 0)
        {
            SAFE_DELETE_ARRAY(szSrc);
            SAFE_DELETE_ARRAY(szMatcher);
            return true ;
        }
        else
        {
            SAFE_DELETE_ARRAY(szSrc);
            SAFE_DELETE_ARRAY(szMatcher);
            return false ;
        }
    }


    // 找到通配符的位置,将通配符的位置存放到数组szWildcardPos中,其中数组末存放的是通配符串的长度
    int* szWildcardPos = new int [wildcard_count + 1];
    int j = 0,w = 0;
    while(szMatcher[j])
    {
        if (szMatcher[j] == '*' )
        {
            szWildcardPos[w++] = j;
        }
        j++;
    }
    szWildcardPos[wildcard_count] = len_match; //


    // 匹配字符串
    int nPos = 0;
    bool bMatch = true;
    char* szSubStr = new char [len_match + 1];  // 临时字符串
    int nSubLen = 0;
    for ( int i = 0; i < wildcard_count; ++i)
    {
        // 第一个通配符不在字符串开始,则匹配头字符串
        if (i == 0 && szWildcardPos[0] != 0)
        {
            nSubLen = szWildcardPos[i] ;
            memmove(szSubStr,szMatcher,nSubLen);
            szSubStr[nSubLen] = 0;
            nPos = StringSearch(szSrc,szSubStr);
            if (nPos != 0 || nPos == -1)
            {
                bMatch = false;
                break;
            }
            nPos = nSubLen;
        }
       
        // 最后一个通配符不在末尾,则匹配字符串需要末尾匹配
        if ((i == wildcard_count - 1) && (szWildcardPos[i] != szWildcardPos[wildcard_count]-1))
        {
            nSubLen = len_match - szWildcardPos[i] - 1;
            memmove(szSubStr,szMatcher+szWildcardPos[i]+1,nSubLen);
            szSubStr[nSubLen] = 0;
            nPos = StringSearch(szSrc,szSubStr,len_src-nSubLen);
            if (nPos == -1)
            {
                bMatch = false;
            }
            break;
        }


        int nSubLen = szWildcardPos[i+1] - szWildcardPos[i] - 1;
        if (nSubLen <= 0)
        {
            continue;
        }
       
        memmove(szSubStr,szMatcher+szWildcardPos[i]+1,nSubLen);
        szSubStr[nSubLen] = 0;
        nPos = StringSearch(szSrc,szSubStr,nPos);
        if (nPos == -1)
        {
            bMatch = false;
            break;
        }
    }
  
    SAFE_DELETE_ARRAY(szSrc);
    SAFE_DELETE_ARRAY(szMatcher);
    SAFE_DELETE_ARRAY(szWildcardPos);
    SAFE_DELETE_ARRAY(szSubStr);
    return bMatch;
}  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值