美丽的fnmatch(匹配函数)
时间:2008-09-21
来源:互联网
这个函数的具体用法, 看PHP手册.
这个是框架中为了解决windows不支持fnmatch的问题, 而写的一个fnmatch函数的实现, 暂时不支持[]匹配, 也许哪个有心人可以加上, 如果看得懂算法的话, 加上是不麻烦的.
下面是fnmatch函数的实现(注意, 些函数, 在Linux等一些系统上的PHP已经存在了, 测试时建议改成其它名字):
[php]<?php
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;
}
//下面是测试代码
assertTrue(fnmatch('abcdefg', 'abcdefg'));
assertTrue(fnmatch('abcd?fg', 'abcdefg'));
assertTrue(fnmatch('?bcdefg', 'abcdefg'));
assertTrue(fnmatch('abcdef?', 'abcdefg'));
assertTrue(fnmatch('?bcdef?', 'abcdefg'));
assertTrue(fnmatch('ab??ef?', 'abcdefg'));
assertFalse(fnmatch('abcd?fg', 'abcdeefg'));
assertFalse(fnmatch('abcd??fg', 'abcdefg'));
assertTrue(fnmatch('abcd*fg', 'abcdefg'));
assertTrue(fnmatch('abcd*efg', 'abcdefg'));
assertTrue(fnmatch('ab*fg', 'abcdefg'));
assertTrue(fnmatch('abcdefg*', 'abcdefg'));
assertTrue(fnmatch('abcdefg***', 'abcdefg'));
assertTrue(fnmatch('*abcdefg', 'abcdefg'));
assertTrue(fnmatch('***abcdefg', 'abcdefg'));
assertTrue(fnmatch('abcde*', 'abcdefg'));
assertTrue(fnmatch('*defg', 'abcdefg'));
assertFalse(fnmatch('ab*f1g', 'abcdefg'));
assertFalse(fnmatch('a1b*fg', 'abcdefg'));
assertTrue(fnmatch('??c*fg', 'abcdefg'));
assertTrue(fnmatch('*?bc*f?', 'abcdefg'));
assertTrue(fnmatch('?*bc*f?', 'abcdefg'));
assertTrue(fnmatch('?*c*f?', 'abcdefg'));
assertTrue(fnmatch('?*c*f?', 'a123bcdefg'));
assertTrue(fnmatch('?***c*f?', 'abcdefg'));
assertTrue(fnmatch('**?*c*f?', 'abcdefg'));
assertTrue(fnmatch('*?*?*c*f?', 'abcdefg'));
assertTrue(fnmatch('a*?', 'abcdefg'));
assertTrue(fnmatch('/????*/', '/fdsaffdsaf22/'));
assertTrue(fnmatch('/????*/', '/fdsaffdsaf/'));
assertTrue(fnmatch('/????*/123', '/fdsaf/123'));
assertTrue(fnmatch('/*????/', '/fdsaffdsaf22/'));
assertTrue(fnmatch('/*????/', '/fdsaffdsaf/'));
assertTrue(fnmatch('/*????/123', '/fdsaf/123'));
assertTrue(fnmatch('/??*??/', '/fdsaffdsaf22/'));
assertTrue(fnmatch('/??*??/', '/fdsaffdsaf/'));
assertTrue(fnmatch('/??*??/123', '/fdsaf/123'));
assertTrue(fnmatch('a??*fg???*l*n', 'abcdefghiijklmn'));
assertTrue(fnmatch('a??*fg???*l*n', 'aabcdefgghiijklmn'));
assertTrue(fnmatch('abc??*fg???*l*n', 'abcdefghiijklmbcdefghiijklmn'));
function assertTrue($value)
{
echo $value ? 'Pass<br />' : ('Fail' . debug_print_backtrace() . '<br />');
}
function assertFalse($value)
{
echo $value ? ('Fail' . debug_print_backtrace() . '<br />') : 'Pass<br />';
}
?>
[/php]
为了运行快一些, 这个函数, 不使用递归, 而是直接使用栈.
一般我是不是很喜欢写注释, 因为好的代码, 是不需要什么注释的, 为了让一个新手比较好理解, 我就加上一些注释, 但在算法上, 如果没有理解好算法, 再注释也作用不大.
这个算法复杂度是O(n(n+1)/2), n是被字符串长度.
当匹配式没有通配符时, 复杂度是=n
如果没有*号匹配失败的话复杂度是<=n
当然也欢迎大家来找虫, 如果有发现匹配错误的, 欢迎提交上来, 可以像上面的测试那个写一个assert, 回复本贴就可以了.
1. 修复一些匹配错误
2. 删除array_push()和array_pop(), 以优化运行效率
修改后, 虽然做了优化, 但因为算法做了些改变, 算法复杂度改变了: 原复杂度是O(2n) , 而新算法每次恢复了上一次$string的开始位置, 所在现在复杂度是O(n(n+1)/2)
作者: programmerhuang 发布时间: 2008-09-21
作者: liexusong 发布时间: 2008-09-21
作者: gvtbs 发布时间: 2008-09-22
作者: caixiaxu 发布时间: 2008-09-25
if (!function_exists('fnmatch')) {
function fnmatch($pattern, $string) {
return @preg_match('/^' . strtr(addcslashes($pattern, '\.+^$(){}=!<>|'), array('*' => '.*', '?' => '.?')) . '$/i', $string);
}
}
?>
[php]<?php
if (!function_exists('fnmatch')) {
function fnmatch($pattern, $string) {
for ($op = 0, $npattern = '', $n = 0, $l = strlen($pattern); $n < $l; $n++) {
switch ($c = $pattern[$n]) {
case '\':
$npattern .= '\' . @$pattern[++$n];
break;
case '.': case '+': case '^': case '$': case '(': case ')': case '{': case '}': case '=': case '!': case '<': case '>': case '|':
$npattern .= '\' . $c;
break;
case '?': case '*':
$npattern .= '.' . $c;
break;
case '[': case ']': default:
$npattern .= $c;
if ($c == '[') {
$op++;
} else if ($c == ']') {
if ($op == 0) return false;
$op--;
}
break;
}
}
if ($op != 0) return false;
return preg_match('/' . $npattern . '/i', $string);
}
}
?> [/php]
作者: willko 发布时间: 2008-09-25
但有时候要使用fnmatch的目的就是为了能高效一些, 但又能够做基本的匹配.
正则式很强大, 但没有fnmatch高效.
当然, 我也没有测试我的那个算法会不会比正则式高效. 呵呵.
作者: programmerhuang 发布时间: 2008-09-25
工作完成以后,我在街上逛了一天,给她买生日礼物。最后还是选定了戒指,因为我们认识到现在,需要一个比较有纪念价值的礼物了。精心挑选了一个我认为很漂亮的戒指,手中拿着戒指的时候,想象着她突然见到我的惊喜,亲手给她带上戒指的感动。。。。。。
我走的时候给她说了大约什么时候回来,后来因为事情处理的比较顺利,工作提前几天完成了,想给她一个惊喜,就没有告诉她,在这中间有一个小插曲,生日那天因为我在外地,没有办法陪她,前一天我发短信祝她生日快乐,但是在她生日那天晚上12点忘了发短信了,她很生气,我也很内疚,所以准备回去给她好好补上这个生日。
我乘上了回家的列车。。。。。
下了火车,已经晚上9点了。我就直接到了她住的地方。前一段时间她母亲来看她,和她住在一起,刚好昨天走了。
期待着一场激情的相逢。。。。。
站在她的门口,我先给她打了电话,问她在干什么?她说一个人在家看电视,呵呵,我说,想不想见我?她说:想,天天都在想我,恨不得马上见到我。我说:呵呵,那我就满足你的愿望,你开门吧!
她突然就把电话挂了,我觉得奇怪,就又打,但是关机,于是我敲门,但是没有人开门,我突然有一种不祥的预感。敲了半天还是没有声音,我怀疑她是不是在家,于是下楼到门卫那里问,门卫说她回来了,我问:她一个人吗?门卫用很奇怪的眼神看着我,说好象是一男一女。。。。。。
大脑一片空白,手都在发抖,于是冲上楼疯狂的砸门。。。。。
十分钟后,当我在门口大喊要报警的时候,门终于开了。。。。
看到了她,我第一眼看见她就知道发生什么事了,她的头发是乱的,只穿了一件薄毛衣,没有穿内衣,因为可以清楚的看到她的乳* 我当时就想杀人!!!!!!
我问她:那个男的在哪?她不说话!
我吼到:你让他出来,男人敢做就敢当,她还是不说话!
我说:他自己出来,我可以和平的解决这件事,他要是让我找出来,他今天别想活着出去!
她哭着说:你别这样。。。。。
这时候,里面的门突然开了,一个男的走出来了,大约177左右,比我矮一点,壮实一些,长相不敢恭维。。。。
他站在那,问我想怎么样?
我突然想笑:他竟然来质问我?这是我的女朋友我的家,他问我想怎么样?
我没有理他。
虽然我不是很优秀,如果你要选择真正的幸福,我并不阻止你,每个人都有选择的权利!但是我希望你能找一个比我更优秀的男人!
但是我觉得他根本不在我的视线里,他只是个弱势的男人!他配不上你!在一个比自己强的对手面前失败是值得的,在他面前你就是在侮辱我!
以下是我给女朋友说的话:X,你知道吗?为了能提前几天见到你,我在外地每天加班到凌晨,想给你一个惊喜,我知道,作为你的男朋友,我确实比较粗心,不能天天陪你逛街,陪你吃饭,甚至连在你生日的时候都无法陪在你身边,但是不管在哪里,我每天都在想着你,思念着你,我不在的时候,我都是托我的朋友来看看你,你的每一件事我都是尽力去办,今天回来,一是想给你一个惊喜,二是我们在一起一年了,我希望我们能有个机会确定我们的感情,这枚戒指我是想亲手给你带上的,但是我没想到发生这样的事,你深深伤害了我,你要知道这样的事,对一个男人的打击!
女朋友拉着我,求我给她一次机会!
女朋友一直在哭,那个男的低着头,我说完这些话,准备走了,因为我答应她,如果那个男的自己出来我不会动手,我都有点惊异我的忍耐力。
我笑了笑,如果那个男的真的比我强,我还真会给你一次机会,我对自己是很有自信的,挑战我从来不惧的!但是和这个猪头,我没兴趣(那个男的刚出来的时候我问了他一些基本情况,他还是老实回答了。)
就在我准备走的时候,事情突然发生了变化,对门的一个女的突然冲出来,问我想怎么样?这么晚吵到她了。她出来的时候还贴着面模,吓我一跳,估计我在砸门的时候她应该看见我了,就在火要熄灭的时候,突然有人又来煽风!
我回头看了一眼那个男的,他好象在一边看热闹,虽然没有笑,但是我看出了他的得意!想象1个小时前,他在我的床上上我的女朋友!估计我在砸门的时候他们刚作完,所以连内衣都没穿!
我彻底崩溃了,我一边笑着给对门的那个女的说对不起,一边退回房间,我看见一个折凳,那个男的以为我真的准备走了,还准备穿外衣。。。。。
这时候我直接操起折登,朝那个猪头的脸上砸去。他的脸当时就开花了。虽然他比我壮点,但是一个人要是发狂了,照打。。。。。。
那个对门的女的吓坏了,叫了一声,跑回了自己的屋
凳子,杯子,台灯,换了好几样东西,终于撩倒了那个家伙。于是对着脸就是一顿砸,血也喷了一墙!
直到有点累了,那个男的也没力气还手了,我只问了他一句,干别人女朋友感觉爽不爽?
女朋友一直在旁边,她也吓坏了,连哭都忘了。
我扔下那个家伙,站起来,拿着衣服出了门。
女朋友见我出来了,发疯似的跑出来抱着我,求我不要走,求我原谅她这一次。
那几天天气很冷,她只穿了一件薄毛衣,拼命拉着我,哭。。。。。她求我打她,只要我心里舒服,就打她。
我说:我认识你第一天,我就告诉你,我从来不打女人!
我看着她在寒风中发抖,心里突然感觉很爽!
但是我一低头又看见她明显的乳*,我心里就联想到她和那个猪头在床上,我突然拉着她就进出租车,我要去开房!我要发泄!
车走到半路,突然发现没有带身份证,于是让司机掉头,回家。进了家里,那个猪头已经走了,房子一片狼犄。
不管那么多了,直接扒光了她的衣服,她因为在外面冻的有点久了,有点麻木,只是默默的顺从,我直接就上了!
她喊疼,但是已经没有感情的了!你疼?你知道我心里的疼吗?你知道我心如刀割吗?
我根本没有理她,在继续!她看我和她作爱了,以为我可能会原谅她,所以拼命的迎合我。
我问她:在我砸门的时候是不是你们刚作完?她点点头,我又问:你们总共做过几次?她说:这个重要吗?我说:重要!
她刚开始不说。在我的追问下,她说:就我回来前,就那一次,还被我碰到了。
我问她:你爱他什么?她说:他哪都比不上你,他追了我一年,我都没有答应。只是他一直默默的对我好!还在论坛发了1000个帖子说他很爱我,我有点感动,所以。。。。我以为只有一次,以后就不会再发生了!
我当时就笑了:感动就能上床?发帖子就能让你感动?一次以后就没什么了?今天我要是没回来。是不是你就可以当作什么都没有发生?那我是什么?
于是什么都不再说!就剩发泄了!
这件事该怎么办?我一直在想。。。。。分手吧,这样我就解脱了,和好,不可能,一辈子在那种阴影下生活,我受不了。但是我还是很在乎她的,我该怎么办?
早晨醒来,感觉好象做了一个恶梦,但是看到墙上的血,我知道这是真的,我的手也被划破了,枕头上也是血,起来冲了澡直接去上班心理还在想那个傻X群发的事儿。
混沌的状态一直持续了几天,很晚回家,直接作爱,然后睡觉,直到那天上班,她突然打电话来说,她下面出血,我问严重不,她说一直流,我有点担心,本来不想理,但是实在不忍心,一个女孩在外地工作,什么也没有什么亲人,突然心就软了,于是给头请了个假,直接打车去接她到医院,到了医院,一顿检查,医生说子宫有血肿,最近****太频繁,医生还白了我一眼,说,也不知道心疼自己的女朋友,我只有苦笑,以后注意。带她开了药,送她回家了!
于是分手的事就先搁置了,我想不管怎么样,她现在正在生病,我也有责任,先等她的身体养好吧,这样也对得起她父母对我的嘱托。我见过她的父母,她父母都挺喜欢我的,经常夸我对她的女儿照顾细心周到,我清楚的记得,她父亲拉着我的手说:他和她母亲觉得我不错,希望我继续努力,当时我感觉好幸福。。。。。。
现在想想。。。。。。。。唉。。。。。。
有一天,她在家喝的烂醉,我回去的时候一直在哭,我问她怎么了,她说她不能没有我,让我原谅她,我说:想让我原谅你?好,在我面前给那个男的说清楚,我再考虑!
她直接拿起电话,把那个猪头约了出来,当着我的面告诉他:让他滚,她根本就不喜欢他。。。。。。
我在旁边只是静静的看着,没有感动,没有快意,当时我就一个想法,她要为自己所做的付出代价!
等她们说完了,我把那个猪头叫了过来,当时是在街上,他也是很尴尬。他走了过来,告诉我:希望我能好好照顾女朋友,他退出,我看他流泪了,眼睛也肿着(还没有消)也许他也后悔了,但是一切已经晚了我告诉他:我准备和女朋友分手,但是我现在不会告诉她。
这时女朋友走过来,(她没有听到我们的话),挽着我,回家了!
写完这些的时候,我突然感觉轻松了!一切都结束了!爱情我现在已经不能相信了,女人?原来以为我很了解,现在我才发现,是个青头!
日子就这样持续了大约一个星期吧。有一天,我有事去了趟外地,回来的时候也很突然,我直接回家了,但是她不在,于是给她打电话,问她在哪?
她还以为我在外地,就说:我在家看电视。我觉得挺可笑的,就逗她,一个人呀?她说:恩,好无聊。。。。
我说我给你留言了,她问:在哪?网上?我说你到时候就知道了!于是我挂了电话,在她的抽屉里找纸留言,当我打开最后一个抽屉,我发现里面的套子,竟然有好几个,还是两个牌子。我在她这从来就没有放过套子!再打开她的电脑,发现她居然在网上开博,里面有大量的她的私房照片,虽然每露点,但都挺暴露的,我想这就是裸聊吧,还装了一个叫什么推广小助手的群发软件,去群发推广她的博客,她博客流量相当可观。要是有满意的竟然带回家来,而且还明码标价收费,这个网址是我后来在她电脑中发现的。博客网址是http://blog.sohu.com/llsiurtja 现在已经关了,还有那个论坛群发软件的网址http://www.tgxzs.com
看到这些的时候,我的心是彻底的凉了,于是我给留言,让她自己注意身体,我最近比较忙,过一段时间再来看她!
最近一段时间总是在考虑是不是要再从新开始新的一段感情,女人我是从来没有缺过的,现在要找,至少有5到6个合适的,但是我现在想是不是还要做一个好男人!
以前看到一个帖子,说一个男人一辈子只会认真的爱一次,如果被伤害了,就不会再认真,我也到了放弃责任的边缘。
有一件事,当时是在出差,和几个同事在一起,有一个女同事一直对我比较好,她刚进公司的时候就有很多的同事发起攻击,但都败下镇。还是很惹眼的,她的背景也比较深,其实我也明白她什么意思,那天见完客户,我们都喝醉了,我送她房间,一进到房间,她突然搂住我:说喜欢我。当时其实我也很想,应该说是差点,但是最后我忍住了,当时考虑最多的是我有女朋友,不能这样,我也知道,如果和她在一起,对我的 事业帮助很大的,但是你心里有一个人的时候是很难在容下其她人的,所以我还是拒绝了。
后来她给我发短信说:虽然我拒绝了,但是她愿意等我,因为她喜欢有责任心的男人!
现在想想觉得好笑,责任?当我为了责任付出的时候,我的女朋友却为了感动和别人上床!
生日又到了,给我祝福的人很多,收到了很多礼物,在单位是没有人知道我的生日的,只有以前的朋友和朦胧感情的异性。
呵呵,看来我还是有一点魅力的,至少还不老,等着我的事还有很多,事业的更进一步,在众多的礼物中,找到一份情谊最深的,开始自己的新的一段感情!
堕落吧,白天做一个谦谦君子,晚上做一个禽兽。
好多次我都这么想,但是我害怕伤害别人,我害怕女孩流眼泪!
因为我不想做流氓!我不想做禽兽。
至于那个伤害过我那个的女孩,我希望她还是能幸福的的生活,这是真心话,如果她能再找到一个很爱她的男朋友,我希望她能珍惜这段感情。责任,不仅是给男人的!
作者: 琨凡城 发布时间: 2009-10-07
热门阅读
-
office 2019专业增强版最新2021版激活秘钥/序列号/激活码推荐 附激活工具
阅读:74
-
如何安装mysql8.0
阅读:31
-
Word快速设置标题样式步骤详解
阅读:28
-
20+道必知必会的Vue面试题(附答案解析)
阅读:37
-
HTML如何制作表单
阅读:22
-
百词斩可以改天数吗?当然可以,4个步骤轻松修改天数!
阅读:31
-
ET文件格式和XLS格式文件之间如何转化?
阅读:24
-
react和vue的区别及优缺点是什么
阅读:121
-
支付宝人脸识别如何关闭?
阅读:21
-
腾讯微云怎么修改照片或视频备份路径?
阅读:28