阿里笔试的一道题,当时没时间没做出来,现在补一下。
或许他的考点在正则表达式,不过这样有点太简单了(考场上那么久没用过正则表达式,还真写不出来,毕竟闭卷),所以我就自己写了个匹配算法,具体题目是:
第一行输入一个需要进行匹配的字符串,第二行输入匹配模板。成功匹配就返回1,否则返回0。
其中规定两种特殊符号:‘?’表示任意一个字符,‘*’表示一个或多个任意字符,其余字符均为普通字符。
正则表达式简单,就不解释了,直接看代码:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str = sc.nextLine();
String pattern = sc.nextLine();
System.out.println(filter(str, pattern));
}
static int filter(String str, String pattren) {
String temp1=pattren.replace('?', '.');//替换‘?’
String temp2=temp1.replaceAll("\\*", ".+");//替换‘*’
if(str.matches(temp2))
return 1;
else
return 0;
}
}
第二种我自己写的匹配算法,没有做优化了,只把bug处理了
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str = sc.nextLine();
String pattern = sc.nextLine();
System.out.println(filter(str, pattern));
}
static int filter(String str, String pattren) {
//以下两个变量用来记录str和pattren已经比对到哪个位置了,从左往右进行比对,到最后了就说明匹配结束了
int left_str = 0;
int left_pattren = 0;
//对匹配模板进行遍历,寻找那两种特殊符号
for (int i = 0; i < pattren.length(); i++) {
if (pattren.charAt(i) == '?') {//寻找到特殊符号‘?’时
if (i == left_pattren) {//当此时这个‘?’前面没有任何普通字符时
left_pattren++;
left_str++;
continue;
}
else {//有普通字符时
if (!str.startsWith(pattren.substring(left_pattren, i),left_str))//截取**这个特殊符号**前面的所有普通字符,从left_str开始对str进行比对,这里两个方法都是自带的api.
return 0;//不匹配就返回0
//这是前面这段匹配成功后接下来匹配的起始位置的变化
left_str += (i - left_str + 1);
left_pattren = i + 1;
}
}
else if (pattren.charAt(i) == '*') {//这是‘*’的处理
if (i == left_pattren) {//同上,前面没任何普通字符
left_pattren++;
left_str++;
}
else {
if (!str.startsWith(pattren.substring(left_pattren, i),left_str))//同上
return 0;
left_str += (i - left_str + 1);
left_pattren = i + 1;
}
//这里是和问号不同的地方,因为要考虑到底是匹配一个字符还是多个
i++;
while (i < pattren.length() && pattren.charAt(i) != '?'&& pattren.charAt(i) != '*')//寻找下一个特殊符号
i++;
//再把当前的特殊字符和上面找到的特殊字符之间的普通字符进行比对,和上面有一点点不同
int temp = str.indexOf(pattren.substring(left_pattren, i),left_str);//这里用indexOf,因为只要包含就行了,并返回头字符的位置
if (temp == -1)//说明没有
return 0;
else {
left_str = temp + i - left_pattren;//此时等于头字母的位置再加上这个普通字符的长度
left_pattren = i;//直接跳到去比对下一个特殊字符
}
i--;
}
}
//当上面都没问题时,还需要注意下面的细节:
//上面顺利到达这一步只能说明left_pattren ==pattren.length(),但是不能说明left_str == str.length(),也就是有可能str前面都匹配上了,而后面仍可能还有字符未进行匹配
//还有一种可能是pattren的最后一个字符为‘*’,那么str后面还剩什么都不管了
if (left_str == str.length() || pattren.charAt(pattren.length() - 1) == '*')
return 1;
else
return 0;
}
}
上面代码我自己都觉得写的有点蠢,用了大量的if语句,看起来就很丑。但是不会改,查了下资料,好像和什么DFA呀什么有关系,就是编译原理的东西,不过我没学过,等我有机会了再去完善吧。