阅读:65309回复:51
AdBlock正则表达式实践心得[by kmc](2005/12/16附件更新)
首先,我尚且不懂javascript,以下心得,完全是通过学习正则表达式的文档和实践得出,
写该文的目的之一也是试图消除大家对正则表达式的畏惧心理,从简单之处先入门。 而这其中必定有贻笑大方之处,恳请高手们斧正! 在看本文之前,我在附件中附上了带我进入正则表达式之门的一个基础教程, 和一个“正则表达式的练习器”,建议大家先读此文并粗略的实践一下,因为 下面的文字都站在这篇文章的基础上。 --------------------------------------------------------------------------------------------- 通过对正则表达式的文档的研究,以及对本人Maxthon积累下来的广告过滤条目对应的url的分析, 我有以下几点心得: 1.正则表达式的优势,在于高整合度和高精确度,记做到了代码的简洁,又疏而不漏,唯一的缺点,不过是 可读性略差了一点。 2.理论上说,所有的过滤条目都可以用|符号整合到一条正则表达式过滤器里面去,可是这样既雪上加霜地降低了 可读性,还不可避免地失去了正则表达式高整合度的优势。所以,为了能写出好的正则表达式,分析需要匹配的 文本(在这里就是url了)是必不可少的。 ************************************************************************************* 我们常见的url无非是:aaa.bbb.ccc/123456789/........htm,gif等等 需要过滤的地址,由抽象到具体来说,往往有以下特点: I.全部过滤一个不漏,只要出现就喀嚓,往往是令人深恶痛绝的url。 例(例子中都是用原始的带通配符的表达式):*.ad.*; */ad/*; *.3721.*/*或者*3721* II.过滤网址主体,也就是第一个/号之前的所有。 例:www.1000downloads.com/*; <!-- w --><a class="postlink" href="http://www.w163.com/*">www.w163.com/*</a><!-- w --> III.过滤具体到网页子目录,进入若干个/号内 例:http://imguv.21cn.com/images/*; http://union.homeway.com.cn/images/* 之所以能这样,一般是因为一眼看过去就知道这样的目录下没有好东西,或者看到很多条过滤器中 都出现如下的结构(也表明了网页作者的风格类似),如这里的images IV.过滤具体到文件,一般就是*.gif,*.swf,*.js类的文件了 例:http://images.chinabyte.com/*.swf; http://www.5ud.com/images/*.gif 综上,只要把问题分开考虑即可: ************************************************************************************** 1.一段体 创建一个如下的表达式(注:本文的正则表达式如果不带前后的两个/号,加入adblock时需加上) (\.|\/)(您的输入)(\.|\/|_) (感谢zlowly给出这个filter模型) 前后两个括号中表示的是在你的字段前出现"."或"/",字段后出现".","/"或"_"时候考虑你的字段, 没有这两个限制的话过滤范围就过宽了,例:只写(ad)的话,任何带有ad二字的url均会被过滤。 例: /(\.|\/)(tomnews|dns99|ad|banner|3721|taobao|unionsky)(s)?(\d)*(\.|\/|_)/ --其中的(s)?是表示s出现0次或1次,则该filter通配ad或者ads,banner或banners,但由于 可以出现0次,所以其他成分仍然可以往中间的括号里加入,即便没有unionskys,taobaos。 --后面的(\d)*表示0-9之间的数字,*号表示0次或多次。 正如zlowly所说,为的是对抗网站根据日期显示不同广告,例如 .../ad20041020/... 然后无非是在中间那个括号中,用|号分开你所有想要匹配的字段了。 知道了这一点,后面的情况就势如破竹了。 2.二段体 创建一个这样的表达式雏形: \.()\.() 由于已经具体到网址的主体部分,所以前后的/或者.也就不需再出现了 例: \.(boyis|allyes|cjt1|w163|ppzxw|1000downloads)\.(net|com) 它等价于 http://*.allyes.com/* *.boyis.com* *.cjt1.net* *.w163.com* *.ppzxw.com* *.1000downloads.com* 这样看来,应该比较清晰了吧? 3.三段体 例: (union|adimg|unstat|ulinkjs)\.(baidu|tom|163|sogou)\.(com) 等价于 *adimg.163.com* *unstat.baidu.com* *ulinkjs.tom.com* *union.sogou.com* 或许有朋友问,为什么分开三种情况呢?整合到一起去有没有可能? 一个很自然的想法是用一个"?"号来表示三段体中的第一段或者出现,或者不出现, 例如想要整合admig.163.com和*.boyis.com,这样写的话: (adimg)?\.(163|boyis)\.(com) 因为adimg这个字段可出现也可不出现,所以实际上www.163.com这样的地址自然也会被匹配上了,这可不是我们的初衷, 这也就是为什么我觉得应该把各种情况分开考虑,当然更期待高手能解决这个 问题。 其次,鉴于"|"符号会导致自由组合,整合度不应太高。三段体例子中,第一个括号中最好不要放进通用性太强的字段, 如www,否则"|"符号产生自由组合,若要过滤www.ads8.com和adimage.163.com,自由组合的结果当然www.163.com也被过滤了…… 有鉴于此,锁定某一段应该是一个不错的选择,我看第三段应该锁定,也就是说里面没有“或”符号 例如:结尾为com的全部单独写一条,而不要结尾(com|net|org|biz|gov)全加上, 或许会有意想不到的组合的(大家看看whitehouse.com/net/gov就知道了:)) 4.具体到文件的,swf/gif类(如有FlashBlock这个扩展的,可以不需要重复过滤swf) 下面是一条很个人的filter,原则也就是在()\.()\.()\/的基本型后面加上了一个.*\.(gif|swf)的文件类型判断, 鉴于这个时候网站网址变化很大,这个filter的整合度就不高了,很多都是直接贴进去然后用"|"符号分开而已。 (www\.(mydrivers|btbbt|shd|5ud)\.com(\.cn)?|search(\d)?\.btchina\.net|image\.cgame\.cn| onlinedown\.net|218\.106\.83\.10|down\.20cl\.com)\/(image(s)?|photo)?\/.*\.(gif|swf) 等价于: http://*.onlinedown.net/*.swf http://*.onlinedown.net/images/*.gif http://down.20cl.com/*.gif http://image.cgame.cn/photo/*.gif http://search3.btchina.net/images/*.gif http://www.btbbt.com/*.gif http://www.shd.com.cn/*.gif http://www.mydrivers.com/images/*.gif http://www.mydrivers.com/images/*.swf http://218.106.83.10/images/*.gif ***************************************************************************************************************** 希望拙作能给大家体会正则表达式的强大、学习使用正则表达式带来帮助。 在此最有必要感谢的是AdBlock的(作者(们)?)(0次或1次……呵呵),我在AdBlock的设置中也没找到他(们)?的名字, 网站上也没找到,对这样默默无闻的人表示敬佩。 顺带谢谢提供广告帮助测试AdBlock的所有广告提供商…… |
|
|
1楼#
发布于:2004-11-30 00:19
分析得很透彻。强烈建议置顶加精!
|
|
2楼#
发布于:2004-11-30 00:19
我记得任何一条表达式都必须以“/”开头和结束,这样才能被正常识别,对否?
|
|
3楼#
发布于:2004-11-30 00:19
不错不错,好文章
|
|
|
4楼#
发布于:2004-11-30 00:19
现在我有一个最大的疑问就是白名单的设置
----------- 要匹配pics/*.gif但不要匹配其中的pics/winner[0-9].gif ,表达式怎么写? 我写的是[^winner\d],这时winner[0-9].gif不匹配,达到了 要求,a13.gif匹配,但是型如1234.gif的也不匹配,不知道 为什么……难道是方括号只能接受单个字符? 那我写得更弱智一点:[^w][^i][^n][^n][^e][^r][^\d] ,可是这样不管是1123.gif; a1223.gif; 还是winner4.gif都不匹配了……………… 我当时写的那个Chinaren校友录的 filter经测试是错误的,不能把想要的东西白名单掉的。 看遍了正则表达式的说明文档和例子表达式也没看到如何 剔除大量字符的方法,不知道是不是我秀逗, 大家有什么建议么? ------------------------- 经过测试我实现了这个功能,表达式如下 [^(winner)].*\.gif(1111.gif,a1.gif匹配,winner[0-9]不匹配) 但我总觉得有点取巧的感觉(这里并没有明确排除winner后面的那一位数字), 可一旦我写[^(winner\d)].*\.gif, 型如1111.gif的又不匹配了, 还是没真正搞明白。 |
|
|
5楼#
发布于:2004-11-30 00:19
[^winner]=no:w+i+n+e+r
[^winner\d]=no:w+i+n+e+r+0+1+...+9 白名单目前用黑名单+定向排除(对访问多的有意思,否则也罢。如单列shou.com/cs/xxxx的意义是精确排除) (^xxxxxx)adblock可用,可排除xxxxxx,不过识别的是字符,不是“xxxxx”,还有漏网的 。 adblock的规则对?=,?!不支持,否则ok. |
|
|
6楼#
发布于:2004-11-30 00:19
我试了试,是支持的,^_^,这个正则表达式满足我的要求
且测试通过 images/(?!winner\d).*\.gif 官方论坛关于正则表达式的讨论帖中理解到的: http://aasted.org/adblock/viewtopic.php?t=143 在页面中下部,大概讨论如此: -Conditionals are special characters that insert logic into your pattern. Example-IV: I have three strings: "place", "placed", "placard" Using the OR-conditional /place|placed/, results in positive matches on the first two, but not the third. -Sets are simply the arrangement of one-or-more conditionals inside a parenthesis. Example-V: I have the same strings: "place", "placed", "placard" Using the OR-conditional, this time inside a set /plac(e|ed)/, results in positive matches on the first two, but not the third. -Now, let's make the pattern explicitly exclude the third string, instead of spelling-out the first two. Example-VI: again: "place", "placed", "placard" Using the negative-lookahead /plac(?!ard)/, results in positive matches on the first two, but not the third. Ah- so this is pretty easy. Is there any way to make whole sets conditional?- so that, maybe, nothing in them has to match? Yes- for this, we use multipliers. -Multipliers allow items to be matched multiple-times -- with precision. Whatever directly precedes the multplier is affected. The most common multiplier is the "wildcard" (*). It matches zero or more times. Example-VII: I have three strings: "/YaBBImages/wild.jpg", "/YaBBImages/wilders.jpg", "/YaBBImages/catbg.jpg" Using the word-character and wildcard multiplier /wild(ers)*\.jpg/, results in positive matches on the first two, but not the third. [Note: the period and forward-slash are special-characters in regexp. To access their "literal" meaning, we precede them with a back-slash. This is called literalizing.] -Finally, let's bring it all together: Example-VIII: the same strings: "/YaBBImages/wild.jpg", "/YaBBImages/wilders.jpg", "/YaBBImages/catbg.jpg" Combining everything we know /YaBBImages\/(\w(?!bg))*\.jpg/, results in positive matches on the first two, but not the third. |
|
|
7楼#
发布于:2004-11-30 00:19
多谢楼主分享心得,我也学习了不少,嘿嘿。
关于楼主的这个filter images/(?!winner\d).*\.gif 我觉得这个*号似乎是没有必要的。因为需要匹配除了winner[0-9].gif以外所有的gif,只需要排除winner\d这个就可以了。楼主加了一个*就是指*前面的那个 . 可以重复0次到无限次。没有意义。 不知道说的对不对:) |
|
8楼#
发布于:2004-11-30 00:19
我一看觉得你说的是对的,随手拿正则表达式练习器试了试
去掉.*的表达式:images/(?!winner\d)\.gif 但是不能满足要求,也就是说比如说images/a1.gif就 找不到(虽然winner4.gif什么的一样找不到) 我也不理解为什么,这个.*是我习惯性写上去的,表示的 就是普通表达式里面的通配符*(因为'."表示任何字符-除了 换行符,但url里面没有换行符-,出现零次或多次正好 达到这个目的) 我还是很信赖正则表达式练习器的,它能通过的表达式, Adblock里面都没问题 |
|
|
9楼#
发布于:2004-11-30 00:19
不错不错,多谢楼主分享,对于我等菜鸟实在是大有帮助。另存为先,然后再学习。
|
|
|
10楼#
发布于:2004-11-30 00:19
嗯,我好像还没有很好的理解正则表达式。楼主加.* 是对的,这样可以完全匹配。如果没有的话匹配的就是这样的表达式了:images/.gif
不过看老外写的filter中/前面都有\的,不过好像没有什么必要,我用练习器试了试发现 images\/(?!winner\d).*\.gif images/(?!winner\d).*\.gif 作用是相同的~~ |
|
11楼#
发布于:2004-11-30 00:19
太好了!简直就是我的救星!
|
|
|
12楼#
发布于:2004-11-30 00:19
反斜杠\是转义字符,因为正斜杠/用来表示正则表达式的开始和结束,它在正则表达式中有特殊作用(类似于程序设计中的
保留字,好比在C语言中不能定义一个变量叫做int一样), 所以要表示url中的正斜杠/,要加上反斜杠\来限定,同样的 情况会出现在句号.上,因为正则表达式中.号表示任何一个字符, 所以url都会写成www\.sina\.com\.cn这样的形式, 虽然写成www.sina.com.cn不会出现问题,但只说明这是 巧合而已,因为不会有什么网站叫做www1sina2com3cn的。 |
|
|
13楼#
发布于:2004-11-30 00:19
反斜杠\是转义字符,因为正斜杠/用来表示正则表达式的开始和结束,它在正则表达式中有特殊作用(类似于程序设计中的
保留字,好比在C语言中不能定义一个变量叫做int一样), 所以要表示url中的正斜杠/,要加上反斜杠\来限定,同样的 情况会出现在句号.上,因为正则表达式中.号表示任何一个字符, 所以url都会写成www\.sina\.com\.cn这样的形式, 虽然写成www.sina.com.cn不会出现问题,但只说明这是 巧合而已,因为不会有什么网站叫做www1sina2com3cn的。 |
|
|
14楼#
发布于:2004-11-30 00:19
to kmc:
Adblock支持Java正则来过滤匹配,但Java正则有点不一样或者说简单一些。 你一直在用常规正则表达式(包括那个练习器)练习Adblock过滤,难怪不出问题。 |
|
上一页
下一页