Wildcard Characters |
Time Limit: 1000ms, Special Time Limit:2500ms, Memory Limit:32768KB |
Problem description |
In computer (software) technology, a wildcard character can be used to substitute for any other character or characters in a string. The asterisk (*) usually substitutes as a wildcard character for any zero or more characters, and the question mark (?) usually substitutes as a wildcard character for any one character, as in the CP/M, DOS, Microsoft Windows and POSIX (Unix) shells. (In Unix this is referred to as glob expansion.) For example: a string "wildcard" can be matched by expression "*", "**", "????????", "?ildcar?", "*card", "?ild*d", etc. |
Input |
The first line of input contains a non-negtive integer t(1 <= t <= 1000), then followed t lines, each contains a single word(composed by alphabet characters, digits or underlines "_", and no longer than 10 characters), the next line contains a non-negtive integer n(1 <= n <= 30), then followed n lines, each line is an expression, which my contain some wildcard characters. |
Output |
For each expression, you should output the number of words that matches this expression.(the match is case-insensitive). |
Sample Input |
5 perl public python pearl private 4 p* ?????? *l *i* |
Sample Output |
5 2 2 2 |
解题思路:
这题开始编写的时候,我很快陷入那种填补式代码的困境,就是不断的调试,发现一个错误然后纠正下代码,又调试,又纠正,最后代码基本上失去管理。。。于是我索性把那些代码全部删除了,整理下思路并在纸上表示出。终于AC了 。。呵呵,思路是最重要的。另外平时练习ACM也应该注意代码的可读性和可复用性。
首先含通配符的串归结为两类:以 * 开头, 以?cc 即不含* 开头的子串开头。对?cc 这一类,我们先找到一个匹配的串,此后以该串后的开始位置匹配后面的串。统一以*开始匹配,我们选出两个*之间(也含*到结尾)的串进行匹配,匹配成功则记录该串的值; 否则就匹配失败。 我们只记录最后的这种串。扫描完表达式串后,如果原串匹配完,或者表达式串的最后一个字符是*则匹配成功,否则在原串的最后位置匹配保存的串。原理: * 后面的串可以是原串后面的任意匹配串。。
如: 原串 str 为: agksdjfDFSgskjfkKKK 表达式 exp 串为: *dj*df*??jfk*
匹配过程: 扫描表达式串 exp 第一位置为 * ,
找到子串 dj 匹配位置: i=4 , 保存到字符串 lastSubstr = "dj"
继续扫描 exp (从 dj后面开始扫), 找到子串 df(DF) ,忽略大小写比较 lastSubstr="df"
…… 最后lastSubstr="??jfk", 因为 exp 的最后字符为 * ,匹配成功;
另: 如果 str = "aksfjkskdfjkslSKD" exp="aks*jk*Skd"
首先 aks = aks ,exp="*jk*Skd"( 前面的可以不管了)
lastSubstr = jk, 最后 lastSubstr = "Skd". 在 str 的 skdfjkslSKD 匹配, str 剩余串为
dfjkslSKD, 因为 exp 的最后字符不是 *, 则 lastSubstr 必须与 str 的剩余串尾部匹配这里是 "Skd"="SKD", 匹配成功。
//////// 代码 //////////
#include <iostream>
#include <string>
using namespace std;
const int CSTR_LENGTH = 20;
char gStr[1000][CSTR_LENGTH];
/* 串匹配辅助函数(在 cstr 里查找 str 子串)
* 参数: i cstr 的起始匹配下标(匹配成功则返回起始位置)
* it 用于返回子串在 cstr 中的最后位置
* str 待匹配子串串,可能含有通配符 ?
* cstr 原串
* 返回值: 匹配成功则返回true,同时i,it记录匹配位置, 否则 false
**/
bool searchMatch(unsigned int& i, unsigned int& it,
const string& str, const char cstr[]){
unsigned int si, j;
for(si=i; cstr[si]!=NULL; si++){
for(it=si,j=0; j<str.size() && cstr[it]!=NULL &&
(str[j]=='?' || str[j]==cstr[it]); j++)
it++;
if(j>=str.size()){
i=si;
return true;
}
}
return false;
}
/* 通配符匹配串函数(长度不限)
* 参数: str[], 待匹配的C风格字符串(以NULL结尾)
* exp[], 含有通配符 ? * 的C风格字符串
* isCase : false 忽略大小写匹配, true 区分大小写
* 返回值: 如果 exp 可以匹配 str 则返回 true ,否则 false
* 注意:该函数在忽略大小写比较时,会改变原串
**/
bool isMatch(char str[], char exp[], bool isCase){
/// 是否忽略大小写匹配,是,则全部转为小写形式
if(!isCase){
char *p;
for(p=str; *p!=NULL; p++){
if(isupper(*p))
*p = tolower(*p);
}
for(p=exp; *p!=NULL; p++)
if(isupper(*p))
*p = tolower(*p);
}
/// 空串处理,空串或者 “**...*”可以匹配空串
if(str[0]==NULL){
int j;
for(j=0; exp[j] && exp[j]=='*';)
j++;
return exp[j]==NULL;
}else if(exp[0]==NULL)
return false;
/// 如果 exp 不以 * 开始,则先匹配开始部分
unsigned i, j, it, jt;
for(i=j=0; str[i]!=NULL&&exp[j]!=NULL&&exp[j]!='*'; i++,j++){
if(exp[j]!='?' && str[i]!=exp[j])
return false;
}
if(str[i]==NULL){
for(; exp[j] && exp[j]=='*';)
j++;
return exp[j]==NULL;
}else if(exp[j]==NULL)
return false;
/// 扫描 以 * 开始的串,进行匹配
string lastSubstr;
for(jt=j; exp[jt]!=NULL ; i=it,j=jt){
for(; exp[j]!=NULL && exp[j]=='*';)
j++;
if(exp[j]==NULL)
break;
for(jt=j; exp[jt]!=NULL && exp[jt]!='*';)
jt++;
string tmp(&exp[j],&exp[jt]);
if(!searchMatch(i,it,tmp,str))
return false;
lastSubstr = tmp;
}
/// 最后一个子串(exp中的)处理。
if(exp[j-1]=='*')
return true;
for(i=strlen(str)-lastSubstr.length(),j=0; j<lastSubstr.length(); i++,j++)
if(lastSubstr[j]!='?' && str[i]!=lastSubstr[j])
return false;
return true;
}
int main(){
int n, m;
char str[CSTR_LENGTH];
cin>>n;
for(int i=0; i<n; i++)
cin>>gStr[i];
cin>>m;
int j, match;
for(; m--; ){
cin>>str;
for(match=j=0; j<n; j++)
if(isMatch(gStr[j],str,false))
match++;
cout<<match<<endl;
}
return 0;
}
评论