通配符匹配

在网上看到通配符匹配的[url=http://www.nsftools.com/tips/CTips.htm]C语言实现[/url],代码很漂亮。如果使用递归,代码可以更清晰一些,以下是我修改之后的代码:

int wildcard_matches(const char *wildcard, const char *str) {
if (*wildcard == '\0')
return *str == '\0';
if (*wildcard == '?')
return wildcard_matches(++wildcard, ++str);
else if (*wildcard == '*') {
for (++wildcard; *str; ++str)
if (wildcard_matches(wildcard, str))
return TRUE;
return *wildcard == '\0';
} else
return *wildcard == *str && wildcard_matches(++wildcard, ++str);
}

我曾用java实现过通过符匹配,思想是将wildcard用'*'分割成多个部分,然后对每个部分进行匹配,因为时间效率可以达到O(k),这种算法看起来效率更高(对此我十分怀疑),但实现却比上面要复杂得多,花了差不多一个下午才实现并测试完毕,中间出现许多bug,多次的bug修复导致代码惨不忍睹,测试通过之后,我不想再碰那个代码。而上面的C语言代码我花了不到一个小时(并不快),中间出现一个bug,但我很快就修复了,实现完成之后,我仔细阅读了代码,深叹其实现之优雅。这就不同代码带来的巨大差异。《代码之美》第一章讲的是一个简易的正则表达式实现,现在看来其优雅程序当然要超过我上面的代码,但我当初却没有太多感觉,仅仅是因为我没有实现过正则表达式。从这点上来说,程序员不仅需要多读优秀的代码,也要经常写代码,哪怕是再重新实现一遍。

好代码的好处是很容易优化,上面的代码使用递归来实现,通过“代码变换”很容易将"尾递归"改成使用"while循环",如下:

int wildcard_matches(const char *wildcard, const char *str) {
while (1) {
if (*wildcard == '\0')
return *str == '\0';
if (*wildcard == '?') {
++wildcard; ++str;
} else if (*wildcard == '*') {
for (++wildcard; *str; ++str)
if (wildcard_matches(wildcard, str))
return TRUE;
return *wildcard == '\0';
} else {
if (*wildcard != *str)
return FALSE;
++wildcard; ++str;
}
}
}

这几乎是某种直译:将整个body套在while(1)循环中,然后删掉尾递归。再通过一些“代码变换”,很容易将上面再简化:

int wildcard_matches2(const char *wildcard, const char *str) {
for (;*wildcard; ++wildcard, ++str)
if (*wildcard == '*') {
for (++wildcard; *str; ++str)
if (wildcard_matches(wildcard, str))
return TRUE;
return *wildcard == '\0';
} else if (*wildcard != '?')
if (*wildcard != *str)
return FALSE;
return *str == '\0';
}

上面的代码仍然易懂,只比递归版本要稍微复杂一点,重要的是从递归版本变成迭代版本并不费力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值