带通配符的字符串匹配问题

  1 /*
  2 不使用c,c++库,?表示任意一个,*表示>=0任意,匹配规则要求匹配最大的字符子串,例如a*d ,匹配abbdd而非abbd,即最大匹配字符串
  3 input :abcadefg
  4 reule : a?c
  5 ouput : abc
  6
  7 input : newsadfanewfdsdsf
  8 rule :new
  9 output: new new(最后一个不带空格,中间用空格分隔)
 10
 11 input : breakfastfood
 12 rule  : f*d
 13 output: fastfood
 14
 15 input : aaa
 16 rule  :aa
 17 outpur: aa
 18
 19 input : asdfgsdf
 20 rule  :*
 21 output :asdfgsdf
 22 方法有两种,一种采用递归的方法,最大匹配函数,然后用调用给匹配算法,该函数都返回匹配个数,不匹配返回-1,以input的第一个开始算起,不匹配直接
 23 -1,然后顺序遍历方法。
 24 方法二:采用dp解决,dp问题dp[i][j]表示字符串1和字符串2分别以i和j结尾匹配最大长度
 25 */
 26
 27 #include <iostream>
 28 #include <string>
 29 using namespace std;
 30
 31 int strleng(const char * A)
 32 {
 33     if(A==NULL)
 34         return 0;
 35     const char * p=A;
 36     while(*p!=‘\0‘)
 37     {
 38         p++;
 39     }
 40     return int(p-A);
 41 }
 42
 43 void strcpn(char * a,const char * b,int len)           //注意b里没有‘\0’,a的长度实际为len+1,多了‘\0‘
 44 {
 45     while(len>0)
 46     {
 47         *a=*b;
 48         a++;
 49         b++;
 50         len--;
 51     }
 52     *a=‘\0‘;
 53 }
 54
 55 char * strjoin(const char * a, const char * b,int lenb)
 56 {
 57     char * tmp;
 58     int lena=strleng(a);
 59     if(a==NULL)
 60     {
 61         tmp= new char[lenb+1];
 62         strcpn(tmp,b,lenb);
 63     }
 64     else
 65     {
 66         tmp=new char[lena+lenb+2];              //长度为 lena加lenb多了一个空格和一个‘\0‘
 67         strcpn(tmp,a,lena);
 68         *(tmp+lena)=‘ ‘;
 69         strcpn(tmp+lena+1,b,lenb);
 70         delete[] a;
 71     }
 72     return tmp;
 73 }
 74
 75 int canMatch(const char * input ,const char * rule)            //返回最大匹配个数,递归函数
 76 {
 77     if(*rule==‘\0‘)                       //rule必须在input的前面判断啊,啊啊啊啊
 78         return 0;
 79     if(*input==‘\0‘)
 80         return -1;
 81     int r=-1,may;                    //r为该次返回值,may没往后的递归返回值,r根据may最中取值
 82     if(*rule==‘*‘)
 83     {
 84         r=canMatch(input,rule+1);
 85         if(*input!=‘\0‘)
 86         {
 87             may=canMatch(input+1,rule);
 88             if(may>=0&&++may>r)
 89                 r=may;
 90         }
 91     }
 92     if(*rule==‘?‘||*rule==*input)
 93     {
 94         may=canMatch(input+1,rule+1);
 95         if(may>=0&&++may>r)
 96             r=may;
 97     }
 98     return r;
 99 }
100
101 char * my_find(const char * input ,const char * rule)
102 {
103     int len=strleng(input);
104     int * match=new int[len];        //match[i],记录匹配数例如:input:aabbddf rule:a*d output:aabbdd match为:6,5,-1,-1,-1,-1,-1,所以要记录最大的
105     int maxpos=0;
106     char * result=NULL;
107     for(int i=0;i<len;i++)
108     {
109         match[i]=canMatch(input+i,rule);
110         if(match[i]>match[maxpos])
111             maxpos=i;
112     }
113     if(match[maxpos]<=0)              //不存在匹配,必须的有才行,开始都错了
114     {
115         result=new char;
116         result[0]=‘\0‘;
117         return result;
118     }
119     for(int i=0;i<len;)
120     {
121         if(match[i]==match[maxpos])   //用相等好,因为有可能有多个match[i]等于最大值,用maxpos就错了
122         {
123             result=strjoin(result,input+i,match[maxpos]);
124             i+=match[maxpos];               //这样就直接跳过了后面匹配的,例如:a(1)a(2)a(3) a(1)a(2),匹配完aa后直接跳过a(2),到a(3)
125 //            i++;                                       //这样就会是aa aa ,题目的跳过匹配的原来就是这个意思啊
126         }
127         else
128             i++;
129     }
130     delete[] match;
131     return result;
132 }
133
134 /*
135 方法二:采用动态规划方法dp[i][j]表示字符串1和字符串2分别以i和j结尾匹配的最大长度
136 例如:input:abccde  rule:a?c
137        a  ?  c
138     0  1  2  3 (rule)
139   0 0 -1 -1 -1
140 a 1 0  1 -1 -1
141 b 2 0 -1  2 -1
142 c 3 0 -1 -1  3
143 c 4 0 -1 -1 -1
144 d 5 0 -1 -1 -1
145 e 6 0 -1 -1 -1
146 (input)
147 找最后一列的最大的数,即找出以rule最后一个结尾匹配的最大值(例如abccd 和*c,所以要最大值),解决时注意,记录起点和多个的情况
148 */
149
150 char * my_find2(const char * input,const char * rule)
151 {
152     if(input==NULL||rule==NULL)
153         return NULL;
154     int len_input=strleng(input);
155     int len_rule=strlen(rule);
156     int ** dp=new int * [len_input+1];
157     int may;
158     for(int i=0;i<=len_input;i++)
159         dp[i]=new int[len_rule+1];
160     for(int i=1;i<=len_rule;i++)
161         dp[0][i]=-1;
162     for(int i=0;i<=len_input;i++)
163         dp[i][0]=0;
164     for(int i=1;i<=len_input;i++)
165         for(int j=1;j<=len_rule;j++)
166         {
167             if(rule[j-1]==‘*‘)                  //注意是j-1而不是i-1
168             {
169                 dp[i][j]=-1;                      //a*c 和bfc这种情况
170                 if(dp[i-1][j-1]!=-1)
171                     dp[i][j]=dp[i-1][j-1]+1;
172                 if(dp[i-1][j]!=-1&&dp[i-1][j]+1>dp[i][j])
173                     dp[i][j]=dp[i-1][j]+1;
174             }
175             else if(rule[j-1]==‘?‘)
176             {
177                 if(dp[i-1][j-1]!=-1)
178                     dp[i][j]=dp[i-1][j-1]+1;
179                 else
180                     dp[i][j]=-1;
181             }
182             else
183             {
184                 if(dp[i-1][j-1]!=-1&&input[i-1]==rule[j-1])
185                     dp[i][j]=dp[i-1][j-1]+1;
186                 else
187                     dp[i][j]=-1;
188             }
189         }
190         int m=-1;
191         int count_ans=0;
192         int * ans=new int[len_input];
193         char * result=NULL;
194         for(int i=1;i<=len_input;i++)
195         {
196             if(dp[i][len_rule]>m)
197             {
198                 count_ans=0;                       //因为要找最大的,所以每次发现都将count_ans置为0
199                 m=dp[i][len_rule];
200                 ans[count_ans++]=i-m;             //更新ans[0]的值,然后count_ans等于1
201             }
202             else if(dp[i][len_rule]!=-1&&dp[i][len_rule]==m)            //有多个等于m的情况,说明有多个
203             {
204                 ans[count_ans++]=i-m;                  //count_ans更新,并且记录起始位置
205             }
206         }
207         if(count_ans!=0)
208         {
209             for(int i=0;i<count_ans;i++)
210             {
211                 result=strjoin(result,ans[i]+input,m);
212             }
213
214         }
215         else          //说明没有匹配的,返回空字符串
216         {
217             result=new char;
218             result[0]=‘\0‘;
219         }
220         for(int i=0;i<=len_input;i++)
221             delete[] dp[i];
222         delete[] dp;
223         return result;
224 }
225
226 int main()
227 {
228     //char  *input="newsadfanewfdadsf";
229     //char * rule="new";
230     string input[]={"abcadefg","newsadfanewfdadsf","breakfastfood","asdfasdf","aaaaaaa"};
231     string rule[]={"a?c","new","f*d","adfe","a"};
232     int n=5;
233     for(int i=0;i<n;i++)
234     {
235         cout<<my_find2(input[i].c_str(),rule[i].c_str())<<endl;
236     }
237     //cout<<my_find(input,rule)<<endl;
238     system("pause");
239 }
时间: 2024-10-14 18:35:23

带通配符的字符串匹配问题的相关文章

COJN 0558 800600带通配符的字符串匹配

800600带通配符的字符串匹配 难度级别:B: 运行时间限制:1000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 通配符是一类键盘字符,当我们不知道真正字符或者不想键入完整名字时,常常使用通配符代替一个或多个真正字符.通配符有问号(?)和星号(*)等,其中,“?”可以代替一个字符,而“*”可以代替零个或多个字符.你的任务是,给出一个带有通配符的字符串和一个不带通配符的字符串,判断他们是否能够匹配.例如,1?456 可以匹配 12456.13456.1a45

openjudge6252 带通配符的字符串匹配

描述 通配符是一类键盘字符,当我们不知道真正字符或者不想键入完整名字时,常常使用通配符代替一个或多个真正字符.通配符有问号(?)和星号(*)等,其中,“?”可以代替一个字符,而“*”可以代替零个或多个字符. 你的任务是,给出一个带有通配符的字符串和一个不带通配符的字符串,判断他们是否能够匹配. 例如,1?456 可以匹配 12456.13456.1a456,但是却不能够匹配23456.1aa456: 2*77?8可以匹配 24457798.237708.27798. 输入输入有两行,每行为一个不

带通配符的字符串匹配(动态规划)

OJ地址:http://noi.openjudge.cn/ch0206/6252/ 1 #include<string> 2 #include<cstdio> 3 #include<iostream> 4 using namespace std; 5 string A,B; 6 bool Judge(int a,int b); 7 void Init(); 8 int main() 9 { 10 // cin>>A>>B;//A with ? o

动态规划 | 带有通配符的字符串匹配(浅显易懂)

带有通配符的字符串匹配 一.Leetcode | 44 Wildcard Matching(只有一个字符串包含通配符) 题目很简单,就是说两个字符串,一个含有通配符,去匹配另一个字符串:输出两个字符串是否一致. 注意:'?'表示匹配任意一个字符,'*'表示匹配任意字符0或者多次 首先,我们想到暴力破解.如果从头到尾的破解,到第二个字符时,是否匹配成功取决于第一个字符是否匹配成功! 所以我们想到应该要用到动态规划: 既然用到动态规划,最重要的是设置初值 和找到递推式: 于是,我们开始分析初值怎么设

[OpenJudge]带有通配符的字符串匹配

#include <iostream> #include <stdlib.h> #include <string.h> using namespace std; /* 字符串匹配 ?代表一个字符(不能没有),*可以代表任意多个字符(可以为空) ?表示任意字符,也就是说?永远可以匹配成功,本质上,只要遇到?就一定匹配 *的本质,是分割字符串,即如果P=P1*P2,即P得匹配条件是匹配P1串之后,再匹配P2子串 */ //@param  src[], 带匹配的字符串 //@

含有通配符的字符串匹配

字符串匹配问题,给定两个字符串.求字符串2.在字符串1中的最先匹配结果.字符串2中能够存在'*'符号,且该符号能够代表随意字符,即字符串2中存在通配符. e.g. 输入:abcdefghabef, a*f 输出:abcdef #include <iostream> #include <string> using namespace std; bool Match(const string &s1,const string &s2,string &result

含通配符的字符串匹配问题

题目: 给定两个字符串,求字符串2,在字符串1中的最先匹配结果.字符串2中 可以存在'*'符号,且该符号可以代表任意字符,即字符串2中存在通配符. 例如:输入:abcdefghabef,a*f 输出:abcdef #include<iostream> #include<string> using namespace std; int main() { int i=0,len=0,len1,len2,j=0,begin=0; string s,s1,s2,s3; getline(ci

【python cookbook】【字符串与文本】3.利用shell通配符做字符串匹配

问题:当工作在Linux shell下时,使用常见的通配符模式(即,*.py.Dat[0-9]*.csv等)来对文本做匹配 解决方案:fnmatch模块提供的两个函数fnmatch().fnmatchcase() #fnmatch()的匹配模式所采用的大小写区分规则和底层文件系统相同(根据操作系统的不同 而不同) #fnmatchcase()的匹配模式区分大小写 >>> from fnmatch import fnmatch,fnmatchcase >>> fnmatc

Python实用技法第22篇:利用Shell通配符做字符串匹配

1.需求 当工作在UNIX Shell下时,我们想使用常见的通配符模式(即:.py,Dat[0-9].csv等)来对文本做匹配. 2.解决方案 fnmatch模块提供了两个函数:fnmatch()和fnmatchcase(),可用来执行这样的匹配,使用起来非常简单. 实例: from fnmatch import fnmatch,fnmatchcase print(fnmatch('mark.txt','*.txt')) print(fnmatch('mark.txt','?ark.txt'))