python带通配符的字符串匹配算法_通配符的字符串匹配算法

本文介绍了Python中处理带通配符的字符串匹配问题的算法,通过将字符串按'*'和'?'切分,然后使用KMP算法进行匹配。文章详细分析了处理'?'和'*'的方法,并提供了代码实现,包括KMP算法的改进以及匹配所有结果的输出策略。
摘要由CSDN通过智能技术生成

1. 简述

题目描述:

Str1中可能包含的字符:除了'*'和'?'以外的任意字符。

Str2中可能包含的字符:任意字符。其中,'?'表示匹配任意一个字符,'*'表示匹配任意字符0或者多次。

给出这样两个字符串,判断Str2是否是Str1的子串,如果是输出第一个匹配到的子串,如果不是,输出"不是子串"。

2. 分析

对于'?'的处理,只要在匹配的时候将代码由:if(str1[i]==str2[j]) 改为 if(str1[i]==str2[j] || str2[j]=='?')即可。

对于'*'的处理,可以将str2根据其中的'*'分为若干个片段,然后依次在str1中分别匹配这几个片段即可,而且对于这几个片段分别匹配,如果第k个片段在str1中匹配不到,后面也可以结束了。这里举例说明一下:对于str1="Oh year.Totay is weekend!",str2=*ye*a*e*",实际上就是在str1中匹配"ye","a","e"这三个片段。

Oh year.Totay is weekend!

yea                e

yea                  e

yea                     e

ye         a        e

ye         a         e

ye         a             e

实际上,能够匹配到上面6种情况,按照我们的如果从左到右的匹配每个片段返回的是第一种情况。这里主要分析这种情况的处理,对于所有情况的输出后面再简单说明一下。

首先处理str2,根据'*'分成若干个部分,然后依次在str1中进行匹配,使用kmp算法即可。这样判断能否匹配或者只找第一个匹配的子串的负责度是O(m+n)

3. 代码实现

其中利用了kmp算法,为了使用方便,稍微改了下kmp算法的输入参数,即pat字符串的长度不用'\0'确定,用指定参数确定。

#include#includeusingnamespacestd;//KMP算法,pat长度由len_pat指定voidget_next(constcharpat[],intnext[],intpat_len) {//int len = strlen(pat);intlen=pat_len;inti,j; next[0]=-1;for(i=1; i=0&&pat[i-1]!=pat[j]; j=next[j])

;if(j<0||pat[i-1]!=pat[j])

next[i]=0;elsenext[i]=j+1;//if (pat[i]==pat[next[i]]) next[i]=next[next[i]];}for(inti=0; i

next[i]=next[next[i]];

}

}//KMP算法,str长度由'\0'判断,pat长度由len_pat指定intkmp_next(constchartext[],constcharpat[],intpat_len) {intt_length=strlen(text);//int p_length = strlen(pat);intp_length=pat_len;intt,p;int*next=newint[p_length];

get_next(pat, next, p_length);for(t=0,p=0; t

t++,p++;elseif(next[p]==-1)//说明此时p=0,而且pat[0]都匹配不了t++;elsep=next[p];

}

delete []next;returnt

}//切分pat的结构structPAT_INFO {char*pat;intlen;

};//可以匹配通配符的KMP,返回第一个匹配子串在str中的下标voidKMP_WildCard(char*str,char*pat) {intlen_str=strlen(str);intlen_pat=strlen(pat);inti,j;

dequestore;//切分pat到store中PAT_INFO info;boolnew_info=true;for(i=0; i

new_info=true;

}else{if(new_info) {//需要新建一个infoinfo.pat=pat+i;

info.len=1;

new_info=false;

}else{//不需要新建一个infoinfo.len++;

}

}

}//for//测试切分结果/*while(store.size() > 0) {

info = store.front();

for(i=0; i

cout <

cout <

store.pop_front();

}*///根据切分后的pat序列进行匹配intfirst_index=-1;//起始的下标intlast_index=0;//最后的下标后面的一个位置intnext_index=0;//下一次开始匹配的下标while(store.size()) {

info=store.front();

next_index=kmp_next(str+next_index, info.pat, info.len);if(next_index==-1) {//这个片段没找到,查找任务失败break;

}else{//这个片段找到了,继续找if(first_index==-1) {//找到的第一个片段first_index=next_index;

}

last_index+=next_index+info.len;

next_index=last_index;

}

store.pop_front();//cout <

cout<

cout<

cout<

}

}intmain() {char*str="Oh year.Totay is weekend!";char*pat="*ye*a*e*";

cout<

cout<

cout<

KMP_WildCard(str, pat);

system("PAUSE");return0;

}

4. 所有匹配结果输出

例子:

Oh year.Totay is weekend!

yea                e

yea                  e

yea                     e

ye         a        e

ye         a         e

ye         a             e

首先是所有结果是什么:如果我们要的是str1匹配到的字符串,那么可见实际上上面6个有3个是重复的,因此对于这种情况,只有得到匹配字符串在str1中的开始index和结束index,然后对于重复的去掉即可。如果要的是str1匹配到的字符的下标,那么这是不会重复的。

然后说一下匹配方法,基本上与匹配一个的差不多,不过要加上回溯的过程。比如第一次匹配成功后,继续在新的位置匹配最后一个片段,如果成功了就是第二次匹配成功了,否则就要回溯取在新的位置去匹配倒数第二个片段了,依次类推。直到第一个片段都没法再匹配到,不再回溯了。此外值得注意的是,如果第一次匹配都没成功,就不必回溯了,这种情况下,说明不可能存在匹配结果,因为匹配是从左到右的顺序,都会尽量在左边找到合适的片段,如果第一次都没成功,假设在第k个片段上匹配失败了,那么再回溯的话,轮到k片段是空间实际上只会与上次相同或者更小,大的空间都匹配不到,小的空间更不用说了。

还有一点值得注意:有的一些博文采用的是用str2中一个字符一个字符的匹配,感觉效率会低,而且也没有片段这个方法中的第一次匹配失败就可以停止的规律,也用不了kmp(准确的说是体现不出kmp的优势)。

5. 参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值