不说废话,直接题目:
http://alpha.jpg,http://sub-address/beta.jpg,http://something else/ and http://gamma.jpg,http://delta.jpg
请匹配上述字符串中,不包含gamma字串的其他所有图片的正确地址
捉急的同鞋,请直接看本文最后一行的解决方案……
给大家一个测试网站,有兴趣的同鞋可以自己尝试一下:
另外附加正则表达式的语法手册,方便大家查阅:
http://msdn.microsoft.com/zh-cn/library/ae5bf541(v=vs.80).aspx
下面给出思维过程:
第一步:首先,分解问题,暂且不管gamma的干扰,先想办法匹配所有正确的图片地址,再想办法去掉带有gamma的地址,对于地址的格式,地球人都知道,于是我尝试了这种解决方案:
http://.+\.jpg
思路很简单,以“http://”开头,中间不管,最后以.jpg结尾,但是发现了问题,由于正则表达式默认最长匹配,也叫做贪婪匹配,所以上述解决方案中,我们只会得到一个结果,就是原始串,仔细观察,整个原始串正好符合我们的匹配模式,根据最大匹配的原则,匹配整串是很正常的
第二步:由于最长匹配的干扰,所以我们需要打破这种默认的匹配原则,使其使用最小匹配,也就是非贪婪匹配原则进行匹配,于是我尝试了以下解决方案:
http://.+?\.jpg
根据正则的语法规则,只要在某些特定的限定符之后加一个问号,就可以让解释器使用最小匹配原则进行匹配,所以我们在加号后面加了一个问号,这回我们得到了4个结果,但是有一个结果是有问题的,即gamma图片的结果是有问题的,我们理想的结果应该:
http://gamma.jpg
但是我们得到的结果却是:
http://something else/ and http://gamma.jpg
这个结果有点匪夷所思,按照最小匹配原则,道理上我们应该得到理想结果,但是却没有。这是因为在正则的解释器中,对于最小匹配原则的理解为正向最小匹配,而不是双向最小匹配……
所谓正向最小匹配,就是正则表达式只会在从前向后的匹配中,遵循最小匹配原则,当遇到结尾的匹配模式时立刻停止匹配,但是在匹配的过程中,遇到相同的起始匹配模式时,并不会重新定位匹配的起始位置。简单来说,就是对“hello hello world“进行最小匹配是,解释器不会因为看到了第二个”hello“就认为第二个"hello"是起始位置……
所以,我们面临一个问题,对于这种匹配方式,如果目标文本中含有其他地址(非图片地址)的话,那么我们会将两个地址连起来看作一个地址,这种结果显然是错的……
经过google和百度,我最终也没找到一个让解释器遵循双向最小匹配的方法,所以我们只能用其他方式来解决这个问题了……
第二步半:在得到第三步的正确结果之前,其实我是走了一个小弯路的,最初我打算使用方括号来解决这个问题,于是就有了下面这种解决方案:
http://[\w\-/]+?\.jpg
这种解决方案,虽然解决了得到4个正确地址的问题,但是随之而来的问题更加棘手。我们本来是要通过补集(除了http://)的方式来进行匹配的,而这种方式是给定一个确定集合,进行匹配,这种工作量是巨大的,在我们的实验中除了字母、数字、斜杠和短横杠以外,没有其他字符了,但是现实情况下,url可能是非常复杂的,带有各种特殊符号,甚至包含汉字,那么确定集合的解法就面临着巨大的挑战:1、对于不确定的url没法给出准确的匹配,因为我们不可能预判url中究竟有什么符号;2、匹配模式将会相当的复杂,单纯匹配汉字的模式就是很复杂的
然而,让我放弃这种解法的最直接原因,就是它无法解决排除gamma图片,这个最终问题,因为在正常的思路中,如果我们能排除“http://”,那么我们就能够使用相同的方法排除"gamma",显然这种解决方案无法达到这个目标,毕竟放括号只能匹配单字符,而不能匹配字符串
第三步:在两步半的基础上,我终于找到了正确的出路,字符串排除法,于是有了以下解决方案:
http://((?!http://).)+?\.jpg
这个模式的思路基本符合正常思路:屁排以http开头,.jpg结尾,中间又不存在“http://”的所有字符串,至此,大功告成,我们完美的解决了这个问题
第四步:去掉gamma图片的方式,与去掉http://的方式完全一样, 我们只要将方法照搬就可以得到最终的解法了……
最终解决方案:
http://((?!http://)(?!gamma).)+?\.jpg
原文链接:https://www.f2er.com/regex/362758.html