kmc
kmc
管理员
管理员
  • UID165
  • 注册日期2004-11-25
  • 最后登录2022-09-22
  • 发帖数9186
  • 经验397枚
  • 威望1点
  • 贡献值124点
  • 好评度41点
  • 忠实会员
  • 终身成就
  • 社区居民
阅读:65309回复:51

AdBlock正则表达式实践心得[by kmc](2005/12/16附件更新)

楼主#
更多 发布于:2004-11-30 00:19
首先,我尚且不懂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的所有广告提供商……
附件名称/大小 下载次数 最后更新
正则表达式基础教程.rar (223KB)  3337 2005-07-09 09:46
Waterfox Current和Firefox Nightly都用,逐渐走出XUL扩展依赖
zlowly
狐狸大王
狐狸大王
  • UID376
  • 注册日期2004-11-30
  • 最后登录2010-06-18
  • 发帖数385
  • 经验10枚
  • 威望0点
  • 贡献值0点
  • 好评度0点
1楼#
发布于:2004-11-30 00:19
分析得很透彻。强烈建议置顶加精!
iamgs
  • UID223
  • 注册日期
  • 最后登录
  • 发帖数
  • 经验
  • 威望
  • 贡献值
  • 好评度
2楼#
发布于:2004-11-30 00:19
我记得任何一条表达式都必须以“/”开头和结束,这样才能被正常识别,对否?
Charlie
火狐狸
火狐狸
  • UID27
  • 注册日期2004-11-21
  • 最后登录2006-03-23
  • 发帖数122
  • 经验10枚
  • 威望0点
  • 贡献值0点
  • 好评度0点
3楼#
发布于:2004-11-30 00:19
不错不错,好文章
moZine论坛: http://www.mozine.org
kmc
kmc
管理员
管理员
  • UID165
  • 注册日期2004-11-25
  • 最后登录2022-09-22
  • 发帖数9186
  • 经验397枚
  • 威望1点
  • 贡献值124点
  • 好评度41点
  • 忠实会员
  • 终身成就
  • 社区居民
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的又不匹配了,
还是没真正搞明白。
Waterfox Current和Firefox Nightly都用,逐渐走出XUL扩展依赖
焦油含量中
火狐狸
火狐狸
  • UID97
  • 注册日期2004-11-24
  • 最后登录2011-12-18
  • 发帖数192
  • 经验10枚
  • 威望0点
  • 贡献值0点
  • 好评度0点
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.
FireFox重在体验!时间是体验的基础!
kmc
kmc
管理员
管理员
  • UID165
  • 注册日期2004-11-25
  • 最后登录2022-09-22
  • 发帖数9186
  • 经验397枚
  • 威望1点
  • 贡献值124点
  • 好评度41点
  • 忠实会员
  • 终身成就
  • 社区居民
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.
Waterfox Current和Firefox Nightly都用,逐渐走出XUL扩展依赖
Louis
火狐狸
火狐狸
  • UID72
  • 注册日期2004-11-23
  • 最后登录2005-01-17
  • 发帖数160
  • 经验10枚
  • 威望0点
  • 贡献值0点
  • 好评度0点
7楼#
发布于:2004-11-30 00:19
多谢楼主分享心得,我也学习了不少,嘿嘿。

关于楼主的这个filter
images/(?!winner\d).*\.gif

我觉得这个*号似乎是没有必要的。因为需要匹配除了winner[0-9].gif以外所有的gif,只需要排除winner\d这个就可以了。楼主加了一个*就是指*前面的那个 .  可以重复0次到无限次。没有意义。

不知道说的对不对:)
kmc
kmc
管理员
管理员
  • UID165
  • 注册日期2004-11-25
  • 最后登录2022-09-22
  • 发帖数9186
  • 经验397枚
  • 威望1点
  • 贡献值124点
  • 好评度41点
  • 忠实会员
  • 终身成就
  • 社区居民
8楼#
发布于:2004-11-30 00:19
我一看觉得你说的是对的,随手拿正则表达式练习器试了试
去掉.*的表达式:images/(?!winner\d)\.gif
但是不能满足要求,也就是说比如说images/a1.gif就
找不到(虽然winner4.gif什么的一样找不到)

我也不理解为什么,这个.*是我习惯性写上去的,表示的
就是普通表达式里面的通配符*(因为'."表示任何字符-除了
换行符,但url里面没有换行符-,出现零次或多次正好
达到这个目的)

我还是很信赖正则表达式练习器的,它能通过的表达式,
Adblock里面都没问题
Waterfox Current和Firefox Nightly都用,逐渐走出XUL扩展依赖
SAND
小狐狸
小狐狸
  • UID54
  • 注册日期2004-11-22
  • 最后登录2009-10-20
  • 发帖数98
  • 经验10枚
  • 威望0点
  • 贡献值0点
  • 好评度0点
9楼#
发布于:2004-11-30 00:19
不错不错,多谢楼主分享,对于我等菜鸟实在是大有帮助。另存为先,然后再学习。
行到水穷处 坐看云起时
Louis
火狐狸
火狐狸
  • UID72
  • 注册日期2004-11-23
  • 最后登录2005-01-17
  • 发帖数160
  • 经验10枚
  • 威望0点
  • 贡献值0点
  • 好评度0点
10楼#
发布于:2004-11-30 00:19
嗯,我好像还没有很好的理解正则表达式。楼主加.* 是对的,这样可以完全匹配。如果没有的话匹配的就是这样的表达式了:images/.gif

不过看老外写的filter中/前面都有\的,不过好像没有什么必要,我用练习器试了试发现
images\/(?!winner\d).*\.gif
images/(?!winner\d).*\.gif
作用是相同的~~
agan
火狐狸
火狐狸
  • UID393
  • 注册日期2004-11-30
  • 最后登录2005-08-02
  • 发帖数218
  • 经验10枚
  • 威望0点
  • 贡献值0点
  • 好评度0点
11楼#
发布于:2004-11-30 00:19
太好了!简直就是我的救星!
kmc
kmc
管理员
管理员
  • UID165
  • 注册日期2004-11-25
  • 最后登录2022-09-22
  • 发帖数9186
  • 经验397枚
  • 威望1点
  • 贡献值124点
  • 好评度41点
  • 忠实会员
  • 终身成就
  • 社区居民
12楼#
发布于:2004-11-30 00:19
反斜杠\是转义字符,因为正斜杠/用来表示正则表达式的开始和结束,它在正则表达式中有特殊作用(类似于程序设计中的
保留字,好比在C语言中不能定义一个变量叫做int一样),
所以要表示url中的正斜杠/,要加上反斜杠\来限定,同样的
情况会出现在句号.上,因为正则表达式中.号表示任何一个字符,
所以url都会写成www\.sina\.com\.cn这样的形式,
虽然写成www.sina.com.cn不会出现问题,但只说明这是
巧合而已,因为不会有什么网站叫做www1sina2com3cn的。
Waterfox Current和Firefox Nightly都用,逐渐走出XUL扩展依赖
kmc
kmc
管理员
管理员
  • UID165
  • 注册日期2004-11-25
  • 最后登录2022-09-22
  • 发帖数9186
  • 经验397枚
  • 威望1点
  • 贡献值124点
  • 好评度41点
  • 忠实会员
  • 终身成就
  • 社区居民
13楼#
发布于:2004-11-30 00:19
反斜杠\是转义字符,因为正斜杠/用来表示正则表达式的开始和结束,它在正则表达式中有特殊作用(类似于程序设计中的
保留字,好比在C语言中不能定义一个变量叫做int一样),
所以要表示url中的正斜杠/,要加上反斜杠\来限定,同样的
情况会出现在句号.上,因为正则表达式中.号表示任何一个字符,
所以url都会写成www\.sina\.com\.cn这样的形式,
虽然写成www.sina.com.cn不会出现问题,但只说明这是
巧合而已,因为不会有什么网站叫做www1sina2com3cn的。
Waterfox Current和Firefox Nightly都用,逐渐走出XUL扩展依赖
knover
小狐狸
小狐狸
  • UID56
  • 注册日期2004-11-22
  • 最后登录2008-06-12
  • 发帖数25
  • 经验10枚
  • 威望0点
  • 贡献值0点
  • 好评度0点
14楼#
发布于:2004-11-30 00:19
to kmc:
Adblock支持Java正则来过滤匹配,但Java正则有点不一样或者说简单一些。
你一直在用常规正则表达式(包括那个练习器)练习Adblock过滤,难怪不出问题。
上一页
游客

返回顶部