There are two ways to implement the fnmatch function in this post. The current post is as follows:
function fnmatch($pattern, $string) //$pattern匹配式, $string被匹配的字符串 { $starStack = array(); //创建记录pattern开始位置的栈,这个作用是像编辑器的后退 $sstrStack = array(); //创建记录$string开始位置的栈 $countStack = 0; //栈大小,用一个同步记录栈大小,减少count()时所耗的时间 $ptnStart = strlen($pattern) - 1; //定位匹配式最后一个字符, 算法是从字符串后面开始匹配 $strStart = strlen($string) - 1; //定位字符串的最好一个字符 for(; 0 <= $strStart; $strStart --) //开始匹配循环, 每匹配一个字符, $strStart就往前移一个字符 { $sc = $string{$strStart}; //取得当前在比较的字符 $pc = ($ptnStart < 0) ? '' : $pattern{$ptnStart};//取得匹配式当前的字符,已到结束位置,给个空 if($sc !== $pc) { //当两个字符不相同时, 就要进行一些匹配式特殊字符的比较 if($pc === '*') //如果匹配式当前字符是*号, 进行*号匹配 { while($ptnStart > 0 && ($pc = $pattern{$ptnStart - 1}) === '*') $ptnStart --; //while这段是去除几个连续的*号, 并尝试和取得下一个字符 if($ptnStart > 0 && ($pc === $sc || $pc === '?'))//比较下个字符是否相同或是?号 { //如果下一个字符匹配成功 $starStack[$countStack] = $ptnStart;//保存这个*号的位置 $sstrStack[$countStack] = $strStart;//保存$string开始位置 $countStack ++; //栈向下移一 $ptnStart -= 2; //匹配式定位,前移两位,分别是当前*号位和已经匹配的一个 continue; //进行下一次循环 } } elseif($pc === '?') //如果匹配式当前字符是?号, 进行?号匹配 { $ptnStart --; //?号匹配是字符串同步前移一个位置 } elseif($countStack > 0) //如果不是通配符,检查栈中是否有保存上一个*号的位置 { //有就还原此*号位置, 回到上一个*号处再次进行匹配 $countStack --; $ptnStart = $starStack[$countStack];//还原*号位置 $strStart = $sstrStack[$countStack];//还原$string开始位置 } else { return false; //以上情况都没有的话, 匹配失败, 返回flase } } else { $ptnStart --; //字符串位置和匹配式位置上相同,前移一位,继续下个匹配 } } //匹配循环结束 if($ptnStart === -1) //刚好匹配式的位置也结束, 则匹配成功, 返回true { return true; } elseif($ptnStart >= 0) //匹配式并没有结束, 还有一些没有匹配 { while($ptnStart > 0 && $pattern{$ptnStart} === '*')//检查剩下的是不是都是*号,去除这些*号 $ptnStart --; if($pattern{$ptnStart} === '*') //最后的只有一个*号结束的话, 就匹配成功, 返回true return true; else return false; //否则, 返回false } return false; }
if (!function_exists('fnmatch')) { function fnmatch($pattern, $string) { return @preg_match('/^' . strtr(addcslashes($pattern, '.+^$(){}=!<>|'), array('*' => '.*', '?' => '.?')) . '$/i', $string); } }
I love China
Match I love??
cannot be realized, because the character "China" counts as 4 characters. If it matches I love ????, it should be no problem, but it is very inconvenient for us to use, so I changed it. The implementation of the first function uses the mb_strlen method to count and segment characters. The implementation is as follows:
function fnmatch($pattern, $string) //$pattern匹配式, $string被匹配的字符串 { $encoding = gb2312; //根据自己的页面的编码,来定义这个编码 $starStack = array(); //创建记录pattern开始位置的栈,这个作用是像编辑器的后退 $sstrStack = array(); //创建记录$string开始位置的栈 $countStack = 0; //栈大小,用一个同步记录栈大小,减少count()时所耗的时间 $ptnStart = mb_strlen($pattern, $encoding) - 1; //定位匹配式最后一个字符, 算法是从字符串后面开始匹配 $strStart = mb_strlen($string, $encoding) - 1; //定位字符串的最好一个字符 for(; 0 <= $strStart; $strStart --) //开始匹配循环, 每匹配一个字符, $strStart就往前移一个字符 { $sc = mb_substr($string, $strStart, 1, $encoding); //取得当前在比较的字符 $pc = ($ptnStart < 0) ? '' : mb_substr($pattern, $ptnStart, 1, $encoding);//取得匹配式当前的字符,已到结束位置,给个空 if($sc !== $pc) { //当两个字符不相同时, 就要进行一些匹配式特殊字符的比较 if($pc === '*') //如果匹配式当前字符是*号, 进行*号匹配 { while($ptnStart > 0 && ($pc = mb_substr($pattern, $ptnStart-1, 1, $encoding)) === '*') $ptnStart --; //while这段是去除几个连续的*号, 并尝试和取得下一个字符 if($ptnStart > 0 && ($pc === $sc || $pc === '?'))//比较下个字符是否相同或是?号 { //如果下一个字符匹配成功 $starStack[$countStack] = $ptnStart;//保存这个*号的位置 $sstrStack[$countStack] = $strStart;//保存$string开始位置 $countStack ++; //栈向下移一 $ptnStart -= 2; //匹配式定位,前移两位,分别是当前*号位和已经匹配的一个 continue; //进行下一次循环 } } elseif($pc === '?') //如果匹配式当前字符是?号, 进行?号匹配 { $ptnStart --; //?号匹配是字符串同步前移一个位置 } elseif($countStack > 0) //如果不是通配符,检查栈中是否有保存上一个*号的位置 { //有就还原此*号位置, 回到上一个*号处再次进行匹配 $countStack --; $ptnStart = $starStack[$countStack];//还原*号位置 $strStart = $sstrStack[$countStack];//还原$string开始位置 } else { return false; //以上情况都没有的话, 匹配失败, 返回flase } } else { $ptnStart --; //字符串位置和匹配式位置上相同,前移一位,继续下个匹配 } } //匹配循环结束 if($ptnStart === -1) //刚好匹配式的位置也结束, 则匹配成功, 返回true { return true; } elseif($ptnStart >= 0) //匹配式并没有结束, 还有一些没有匹配 { while($ptnStart > 0 && mb_substr($pattern, $ptnStart, 1, $encoding) === '*')//检查剩下的是不是都是*号,去除这些*号 $ptnStart --; if(mb_substr($pattern, $ptnStart, 1, $encoding) === '*') //最后的只有一个*号结束的话, 就匹配成功, 返回true return true; else return false; //否则, 返回false } return false; }