下面使用动态规划来实现简单的正则表达式匹配。题目如下:

假设?可以匹配任意的一个字符,*可以匹配0到任意个字符,正则表达式只能由数字,英文字母、?和*组成,字符串由英文字母和数字组成,编写一个程序,给定一个满足上述规则的正则表达式和字符串,返回正则表达式是否匹配该字符串。

以下是匹配的例子:

简单匹配算法和朴素匹配算法(算法求解思路培养-10.动态规划之简单的正则表达式匹配算法)(1)

下面看看代码如何写。

用pattern = "hel?o"和 sentence = "hello"进行尝试:

简单匹配算法和朴素匹配算法(算法求解思路培养-10.动态规划之简单的正则表达式匹配算法)(2)

发现pattern[0] = sentence[0],则i和j分别 1,继续判断,直到i=3和j=3,如下图所示:

简单匹配算法和朴素匹配算法(算法求解思路培养-10.动态规划之简单的正则表达式匹配算法)(3)

此时pattern[3] != sentence[3],但由于pattern[i]此时的值为?,可以匹配任意一个字符,因此认为仍然匹配,i和j分别 1,继续往下匹配。

定义表达式dp(i,j)为pattern[i:]和sentence[j:]是否匹配。从上述分析可以看出,如果

pattern[i] == sentence[j] 或者 sentence[j] == "?",则 dp[i][j] = dp[i 1][j 1]。

主要的困难在于*的处理。假设pattern="***bc",sentence="abc",那么,对于第一个*号,可以有以下4种情形:

情形1:不匹配任何字符

简单匹配算法和朴素匹配算法(算法求解思路培养-10.动态规划之简单的正则表达式匹配算法)(4)

情形2:匹配第一个字符

简单匹配算法和朴素匹配算法(算法求解思路培养-10.动态规划之简单的正则表达式匹配算法)(5)

情形3:匹配前二个字符:

简单匹配算法和朴素匹配算法(算法求解思路培养-10.动态规划之简单的正则表达式匹配算法)(6)

情形4:匹配前三个字符:

简单匹配算法和朴素匹配算法(算法求解思路培养-10.动态规划之简单的正则表达式匹配算法)(7)

经过上述分析,可以得出结论:

dp[i][j] = U(dp[i 1][k]), k=j....N。 其中只要有任意一个dp[i 1][k]为True,则

dp[i][j] = True

代码编写如下:

def simple_regex(mod,s,i,j): if i<len(mod) and j<len(s) and (mod[i] == s[j] or mod[i] == "?"): return simple_regex(mod,s,i 1,j 1) elif i == len(mod): return j == len(s) elif mod[i] == "*": for k in range(j,len(s) 1): if simple_regex(mod,s,i 1,k): return True return False print(simple_regex("a*b*c*d****e","athis is a boy and cow and welcome",0,0)) print(simple_regex( "*p*","help",0,0)) print(simple_regex( "*p*","papa",0,0)) print(simple_regex( "*p*","a",0,0)) print(simple_regex( "*p*","p",0,0)) print(simple_regex("he?p","p",0,0)) print(simple_regex("he?p","help",0,0)) print(simple_regex("he?p","heap",0,0)) print(simple_regex("he?p","healp",0,0)) print(simple_regex("*bb*","babbbc",0,0)) print(simple_regex("*bb*p","babbbc",0,0)) print(simple_regex("*bb*","babbbc",0,0)) print(simple_regex("***bb*","b",0,0))

程序输出:

True True True False True False True True False True False True False

按照动态规划的思路,增加缓存,同时将

for k in range(j,len(s) 1): if simple_regex(mod,s,i 1,k):

替换成递归的实现以提升效率,代码如下:

pattern ="t*b*c*d****e" sentence = "this is a boy and cow and welcome" cache = [[-1 for i in range(len(sentence) 1)] for j in range(len(pattern) 1)] def simple_regex(mod,s,i,j): if not (cache[i][j] == -1): return cache[i][j] cache[i][j] = False if i<len(mod) and j<len(s) and (mod[i] == s[j] or mod[i] == "?"): cache[i][j] =simple_regex(mod,s,i 1,j 1) elif i == len(mod): cache[i][j] = j == len(s) elif mod[i] == "*": cache[i][j] = simple_regex(mod,s,i 1,j) or (j<len(s) 1 and simple_regex(mod,s,i,j 1)) return cache[i][j] print(wild_char(pattern,sentence,0,0))

解释下上述代码。

第13行,当mod[i]==‘*’时,我们将循环写成了递归形式。simple_regex(mod,s,i 1,j)表示*号不匹配任何字符。simple_regex(mod,s,i,j 1)表示*号匹配一个字符后,进入下一次递归调用。通过这两个递归组合就完成了

for k in range(j,len(s) 1): if simple_regex(mod,s,i 1,k):

达到的效果。

,