2008.08.24 12:22 am rex
按:本文使用的RegexBuddy为3.1.0(完全)版,并非最新版3.1.1(截至2008.08.23)。需要该版本的请在这篇文章后留言。
注:参考www.regular-expressions.info的风格,更新了本模板的style.css文件,加入了与正则式代码相关的格式:
- 正则式格式举例:[a-z]+@[a-z]+?\.[a-z]+
- 匹配格式举例:pig@animals.com和chicken@birds.com
- 普通文本格式举例:这是一些普通文本。hello regex world. pig@animals.com和chicken@birds.com
可以这样使用:在字符串这是一些普通文本。hello regex world. pig@animals.com和chicken@birds.com使用正则式[a-z]+@[a-z]+?\.[a-z]+加以匹配,得到的结果为:pig@animals.com和chicken@birds.com。
极端粗放型:点号其实是近乎万能的,可以匹配任何字符,限制只在于换行符的匹配上。匹配中文自然不在话下。作为可有可无的背景符,一个.*就能匹配掉包括中文在内的全部字符。这当然是一种极端的情况,因为这样显示不出中文字符串的特性。这不是本文要探讨的。
极端集约型:如果搜索特定文本,例如在一二三四五六七八九十拾佰百千仟万亿中匹配十拾, 直接使用m/十拾/就能搞定。这同样不是本文要探讨的。与\w能匹配英文字母一样,本文想找的是能够匹配所有汉字,而不匹配其它文本的一种简写方式。
普适型型:由于汉字属于Unicode,我们就从unicode里面找。在Unicode Regular Expressions,列出了unicode的许多种表达方式。搜索chinese,找到如下一行:
| Writing Systems |
Blocks |
| … |
… |
| Chinese |
CJK Unified Ideographs, CJK Unified Ideographs Extension A, CJK Compatibility Ideographs, CJK Compatibility Forms, Enclosed CJK Letters and Months, Small Form Variants, Bopomofo, Bopomofo Extended |
关于CJK的含义,是指中日韩统一表意文字(Chinese Japanese Korean Unified Ideographs),可以参考百度释义,或wiki词条。
再查了一下regular expressions,查到其unicode一节有这样的内容:
\p{InCJK_Unified_Ideographs}: U+4E00..U+9FFF
看到这里,我想起了以前写的《匹配用户名的asp正则表达式(包括中文)》一文中,提到的中文匹配为[\u4e00-\u9fa5],原来是有其对应的速记方式的,虽然两者有最后一组字符的差异。看附图可见U+9fa5,最后一个汉字的模样。
此序列的第一位,U+4e00,是汉字一。
自定义:到目前为止,相当于给汉字找到了官方的身份和说法,使用\p{InCJK_Unified_Ideographs}就能匹配所有的中文字符。我们其实也可以将一些重复出现的东西,封装起来,以备使用。例如,对于阿拉伯数字,我们有\d可以用。对于中文数字一二三四等等,我们有没有办法呢?
$zh_digit=qr/一|二|三|四|五|六|七|八|九|十|零|〇|百|千|万|亿|佰|仟|壹|贰|叁|肆|伍|陆|柒|捌|玖|拾/;
$str="人民币五十一万零三百元整。大写:伍拾壹万零三佰元整。";
while($str =~ s/((?:$zh_digit)+)//)
{
print $1."\n";
} |
其输出结果见附图。
结论
可以使用\p{InCJK_Unified_Ideographs}匹配任意中文字符。在不支持该种标记方式时,也可以使用[\u4e00-\u9fa5]加以匹配。
关于文正则表达式,我觉得尚未穷其奥秘。以前在linux(utf8编码)下,编写scim输入平台的郑码码表时,匹配中文所使用的正则表达式为[\x80-\xff]{3},也能很好地工作。请参阅此文:龙文郑码码表 for scim。其原理我尚不清楚,留待之后有时间研究。如有知情者,也请不吝赐教,先行谢过。
2008.05.31 12:07 pm rex
URL
饭否私信分为两种,一种是我收到的私信,一种是我发出的私信。
- 我收到的私信:http://fanfou.com/privatemsg/p.(1-N)
- 我发出的私信:http://fanfou.com/privatemsg/sent/p.(1-N)
上面的地址中不含饭否ID;需要cookie验证。
结束标志
通过cookie验证后,可以使用数字获得对应页码的私信内容。什么时候是结束呢?假如您的收件箱有1000条私信,每页显示20条,那么当你您输入http://fanfou.com/privatemsg/p.51时,就得不到任何有效的内容了。作为程序,它是寻找如下标志:
好友列表
在页面代码中,每页都有一个“向XXX发送私信”的combox列表,条目以昵称+ID组成。如果你的好友很多的话(500+),每条好友(昵称+ID)需要20字节(估算)的话,20*500=10K,大约需要多抓取10K的字节量。
收件箱饭否私信的结构
收到的私信分为两种,一种是有回复信息的(回复原文:…),一种是没有回复的。先从简单的入手,看没有回复的。
所有的私信都在<ol class=”wa”>…</ol>之内,以<li></li>分隔
例如下面这一条,就是一则很规范的私信(与发件人相关的信息都使以正则式表示):
<li>
<a href="/[^"]+" title="[^"]+" class="avatar"><img src="[^"]+" alt="[^"]+" /></a>
来自<a href="[^"]+">[^"]+</a>:
<span class="content">没法比较啊,你得说个具体的值,比如100条以下的算少,1000条以上的算多……</span>
<span class="stamp time" title="2008-05-30 17:25">约 15 小时前</span>
<span class="op">
<a href="/privatemsg.reply/583520">回复</a>
<a href="/privatemsg.del/583520" class="post_act">删除</a></span>
</li> |
其中,需要记录的信息有:
- 发件人名字;
- 发件人ID;
- 私信内容;
- 时间;
- 私信ID;(便于作删除、回复处理)。
根据以上需求,将上面的私信代码作处理:
<li>
<a href="/([^"]+)" title="([^"]+)" class="avatar"><img src="[^"]+" alt="[^"]+" /></a>
来自<a href="[^"]+">[^"]+</a>:
<span class="content">([^<]+)</span>
<span class="stamp time" title="([^"]+)">[^<]+</span>
<span class="op">
<a href="/privatemsg.reply/(\d+)">回复</a>
<a href="/privatemsg.del/\d+" class="post_act">删除</a>
</span>
</li> |
从而得到:
$1=fanfou ID;
$2=fanfou name;
$3=private msg;
$4=msg time;
$5=msg ID; |
再看一下包含“回复原文”的私信的结构(部分内容已作正则处理):
<li>
<a href="/([^"]+)" title="([^"]+)" class="avatar"><img src="[^"]+" alt="[^"]+" /></a>
来自<a href="[^"]+">[^"]+</a>:
<span class="content">([^<]+)</span>
<span class="stamp time" title="([^"]+)">[^<]+</span>
<span class="op">
<a href="/privatemsg.reply/(\d+)">回复</a>
<a href="/privatemsg.del/\d+" class="post_act">删除</a>
</span>
<p class="pm-parent">回复原文: 有兴趣就有动力</p>
</li> |
与前者相比,只是多了<p class=”pm-parent”>.*?</p>这一段。这是不足为虑的。只要整体加上?这个强有力的正则符号,就能与上面的代码片段归纳到一起。两者结合合的代码如下:
<li>
<a href="/([^"]+)" title="([^"]+)" class="avatar"><img src="[^"]+" alt="[^"]+" /></a>
来自<a href="[^"]+">[^"]+</a>:
<span class="content">([^<]+)</span>
<span class="stamp time" title="([^"]+)">[^<]+</span>
<span class="op">
<a href="/privatemsg.reply/(\d+)">回复</a>
<a href="/privatemsg.del/\d+" class="post_act">删除</a></span>
(?:<p class="pm-parent">([^<]+)</p>)?
</li> |
得到的变量为:
$1=fanfou ID;
$2=fanfou name;
$3=private msg;
$4=msg time;
$5=msg ID;
$6=parent msg;#回复原文。 |
发件箱饭否私信的结构
抄代码:
<li>
<a href="/([^"]+)" title="([^"]+)" class="avatar"><img src="[^"]+" alt="[^"]+" /></a>
发给<a href="[^"]+">[^"]+</a>:
<span class="content">海内的像片是真的。</span>
<span class="stamp time" title="2008-05-28 20:24">2008-05-28 20:24</span>
<span class="op"><a href="/privatemsg.del/576827" class="post_act">删除</a></span>
</li> |
这与“我收到的私信”的结构完全一致,只是将原来的“来自”改为“发给”而已。
不出意外,带有“回复原文”的“我收到的私信”的结构是这样的:
<li>
<a href="/([^"]+)" title="([^"]+)" class="avatar"><img src="[^"]+" alt="[^"]+" /></a>
发给<a href="[^"]+">[^"]+</a>:
<span class="content">在自述部分显示的那个网上。</span>
<span class="stamp time" title="2008-05-29 17:00">2008-05-29 17:00</span>
<span class="op"><a href="/privatemsg.del/579918" class="post_act">删除</a></span>
<p class="pm-parent">回复原文: 我也要试一试。</p>
</li> |
我们从饭否私信代码上得到的信息就这些。遗憾的是,饭否私信中,关于“回复原文”是以明文内容形式出现,而不是以原私信ID的形式出现。后期处理时通过搜索功能解决此问题并非不能,只是如果饭否官方能够再将此功能完善的话,会省整理者不少力气。
饭否的私信源码分析完毕。至于如何读写cookie,如何写代码,如何以数据库的形式来管理下载的数据,是第二阶段的事情了。待我一一实现。
2008.05.16 7:48 pm rex
今天收到从淘宝上买来的《精通正则表达式》:第3版(中文版),感觉很爽。加上之前购买的精通正则表达式:第2版(影印版),手头就有两本正则书了。之前那边英文版可是“韦编三绝”,被我读得破破烂烂的了。
2008.04.25 4:07 pm rex
以前在chinaunix回答过这样一个问题,用到了正则表达式(而且我认为正则式解决此类问题是最合适的。)
学英语的一些例句,每句都有若干词根相同的词,例如 She swears to wear the pearls that appear to be pears. 但是每句的词根都未必相同;我希望把这些包含词根的词都标记出来,请问如何写?
这里说的词根不是原本词根的定义,只是一组字母序列,比如
9. The dust in the industrial zone frustrated the industrious man.
词根是dust或ust
10. The just budget judge just justifies the adjustment of justice.
词根是dust
11. I used to abuse the unusual usage, but now I’m not used to doing so.
词根是use,有变形
12. The lace placed in the palace is replaced first, and displaced later.
词根是lace
13. I paced in the peaceful spacecraft.
词根是pace
14. Sir, your bird stirred my girlfriend’s birthday party.
词根是ir
如果您对此问题感兴趣,请独立思考后再继续阅读本站提供的解决方法。
Read More »
2008.04.22 8:26 am rex
2008年4月24日,一个普普通通的日子,iregex.org我爱正则式博客低调开张了。使用的平台是wordpress,面向的受众是对正则式有好感或即将有好感的网友。如果您了解并喜欢正则表达式。如果您不了解、不喜欢正则表达式。
什么是正则表达式?如果您在dos中使用过*和?这两个通配符,那你就理解一半了。正则表达式是一整套通配符。它可以像天书(貌似一堆无意义字符的组合),但也可以简洁高雅。它的作用是高效地搜索和替换字符串。与庞大的操作系统相比,它只是一个小零件。但是,这一零件的作用越来越为人所熟知,越来越不可或缺。
本站关注正则表达式。内容包括原创、转载、翻译与正则表达式有关的教程和应用文章。饭友ppip在自述中说,“因此我将坚持多原创、少转载、少翻译的原则,宁可显出自己的愚钝,也绝不借助于他人的头脑表达。”笔者欣赏这种注重提高自身修养的思想境界。但是本站的宗旨在于分享和交流,同时本人技术并非精尖,所以自矜的仅是对正则式的热爱和对技术的痴迷,因此本站会在坚持原创的同时,不排斥转载和翻译本主题的优秀文章,与各位regexers共享。本人也立志从一名regexer成长为regexist,并最终成为regex guru。
除了正则式,本站还会刊登与搜索引擎有关的文章。Google和百度改变了我们的学习、工作和生活。我们从一个信息贫乏时代跨入了信息泛滥时代。如何精准定位所需的信息,想必也是每位网友所关心的。
为了让更多的人了解、应用正则式这一好用的工具,本站还准备开设一个小型论坛(不日开放),专门用来为新手答疑解惑。首先应该声明的是,本人对于正则式只是叶公好龙,愿意组建平台并抛砖引玉,对于新手的问题知无不言言无不尽;更高深的问题,还望诸多大牛现身赐教;在讨论中相互促进,在解惑中得到提高。
本站的域名为iRegEx.org,i可以理解为I,自己,也可以理解为中文的同音字“爱”。RegEx当然是正则式的意思了。.org是非赢利性组织域名,而非.com。旨在聚拢尽可能多的同道中人,而不是攫取尽可能多的利润。当然,如果本站将来做得足够好,流量足够大,亦不排除出售广告位来达到维持平衡的可能性。我正则,爱正则,我爱正则!
做一个与正则式有关的网站,是本人的一个愿望。现在,这是得偿夙愿的开始。我想以一副长联作为本篇开场白的结语。该长联是本人在饭否上写的“自述”:
◆匹配文本,管它字母数字一次多次懒惰贪婪行首行尾,火眼金睛疏不漏
◆替换字串,任尔局部全局单行多行前瞻回顾大写小写,偷梁换柱度陈仓
希望各位网友多支持“我爱正则式”,多订阅,多评论。谢谢大家。