您的位置:首页 > 其它

Regular Expression Matching

2014-02-19 05:53 417 查看
'.' Matches any single character.

'*' Matches zero or more of the preceding element.

The matching should cover the entire input string (not partial).

The function prototype should be:

bool isMatch(const char *s, const char *p)

Some examples:

isMatch("aa","a") → false

isMatch("aa","aa") → true

isMatch("aaa","aa") → false

isMatch("aa", "a*") → true

isMatch("aa", ".*") → true

isMatch("ab", ".*") → true

isMatch("aab", "c*a*b") → true

使用递归。

对于 pattern p, indexP 对应当前访问的 char, indexP + 1 对应下一个 char.

case 1 : if (p.charAt(indexP + 1) != '*')

如果下一个 char (char at indexP + 1) 不是 ‘*’, 即 if (p.charAt(indexP + 1) != '*'), 那么必须要求当前的 char at indexP 和 char at indexS 是对应的。

例如: s: ...... a b......

p: ...... cc
......

pp+1

这里 index p+1 的位置, char != '*' , 那么如果 在 index p 的位置上不对应, 则直接返回 false, 因为到这一层 p之前的部分匹配成功,但到p 的位置,匹配已经失败了,而且 p + 1 不是 ‘*’, 没法跳过 p。

例如: s: ...... a b
......

p: ...... ac
......

p p+1

在这个例子中,p 的位置对应的 char 是一样的,匹配成功,那么就进入下一层递归调用matchHelper(s, p, indexS + 1, indexP + 1)。
至于 p + 1 位置上的 b 和 c 不对应,那是下一层递归的任务,当进入下一层后,原来的 p + 1 就变成了 p。

case 2 : if (p.charAt(indexP + 1) == '*')

第二种情况是,当下一个 char 是 ‘*’ 时。

此时意味着当前index 对应的 char 可以出现0次或者多次。

但是到底是匹配几个才是最后成功匹配的个数呢?

例如:

s:
a a ab

p: a
* b

用 * 匹配了三个。

s:
a a ab

p: a
* a b

用 * 匹配了两个个。
在没有进行后续部分的比较前,没法确定到底应该用 * 匹配几个,才是应该使用的正确个数。因此方法就是把所有可能匹配上的个数都试一遍。因此 从 0 ~ n 个可以用 * 匹配上 s 的后续的 char 的,都调用一次递归,如果某一种个数最后成功完成了匹配,就 return true, 否则继续用 * 匹配 s 的下一个 char.

直到 s 中 所有可以与当前 * 匹配的都匹配完,即失去与 * 的匹配后,却没有一次成功的匹配并return true. 则跳过 * (indexP + 2),继续后续的递归:

// until we get char at indexS != charAt indexP

return matchHelper(s, p, indexS, indexP + 2);

s s+1s+2s+3s+4

例子: s: ...... a a
a ac ......

p: ...... a*
......

p p+1p + 2

这里 p + 1 是 ‘*’

循环第一次,调用 if (matchHelper(s, p, indexS, indexP + 2)) {return true;},也就是 a* 没有和 s ... s+4 的任何一个a匹配,直接跳过

循环第二次, s++, 此时indexS指在 s + 1. 也就是 a* 匹配了一个 a, 然后跳过a*, 进入后续的比较

循环第三次 s++, 此时indexS指在 s + 2. 也就是 a* 匹配了两个 a, 然后跳过a*, 进入后续的比较

...

(这期间如果有一次的组合是证明成功的,就会return true,因为在 if 里调用了递归)

最后 indexS 到 s + 4(a* 匹配了s中所有可以匹配的a), 此时说明之前的几次都没匹配成功,则继续进入后续的调用:

// until we get char at indexS != charAt indexP

return matchHelper(s, p, indexS, indexP + 2);

public boolean matchHelper(String s, String p, int indexS, int indexP) {
// 当匹配进行到最后,s 和 p的指针超出了末尾
if (indexP == p.length()) {
return indexS == s.length();
}

// 当匹配进行到最后,s 和 p的指针到达了末尾,且相等
if (indexP == p.length() - 1) {
return indexS == s.length() - 1
&& (s.charAt(indexS) == p.charAt(indexP) || p.charAt(indexP) == '.');
}

// next char != '*'
// 若此时 s 和 p 匹配不上,则return false
if (p.charAt(indexP + 1) != '*') {
if (indexS < s.length() && (s.charAt(indexS) == p.charAt(indexP) || p.charAt(indexP) == '.')) {
return matchHelper(s, p, indexS + 1, indexP + 1);
} else {
return false;
}
} else {
// next char == '*'
// 用 while loop 和 递归把所有匹配的个数都尝试一遍
while (indexS < s.length() && (s.charAt(indexS) == p.charAt(indexP) || p.charAt(indexP) == '.')) {
if (matchHelper(s, p, indexS, indexP + 2)) {
return true;
}
indexS++;
}
// until we get char at indexS != charAt indexP
// 之前的递归调用都没有返回 true,
// 此时 * 匹配了当前 s 中后续所有可以匹配的重复char, 跳过 * 继续往后
return matchHelper(s, p, indexS, indexP + 2);
}
}

public boolean isMatch(String s, String p) {
return matchHelper(s, p, 0, 0);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: