关于从普通文本提取正则表达式的再思考

rex按:写完上一篇文章之后,一直在考虑如何真正实现从普通文本中归纳正则表达式的实现。走了许多弯路,也学了不少知识。例如,perl黑豹书上复杂的数据结构、匿名散列和数组、refenrence;紫龙书上的状态机的构造,数据结构上图论的知识,都是很有用的。另外还新学了graphviz的用法。以前觉得很神秘,不过一用才发现很直观。本文的插图是使用online版本的graphviz画的。

除了本文的这种实现方法(基于图),我还使用另一种方式实现了,很简单:基于关键词。具体作法是,逐一读取每一行文本,使用\s+等将其split开,形成array;然后再对所有的array进行求交集的操作(使用hash),得到每一行都有的关键词;然后按从左到右的顺序建立这覆的正则式^(.*?)keyword1(.*?)keyword2….keywordN(.*?)$,再分别匹配每一行文本,得到hash的hash表,或者array的array,转置,并列输出,得到^(option1|option2…)keyword1(option..)…$这样的正则式。最后作为验证,再将所最终生成的正则与每一行匹配测试一下。

这样以词为单位做完之后,再逐个字母地分隔开来,递归地处理(option1|option2…)的部分。先是单词级,再是字母级,有利于先在最大程度上找出重复的内容;而且粗化和细化的处理过程,思路是一致的,粒度不同罢了。

新手请自重,高手请赐教,我的思路未必是正确或最优的。

问题                                                                       

                                                        

有文本文件text.txt,内容如下:
this is a red fox
this is a blue firefox
this is a pig
a red fox
请写一则程序,根据文本内容,自动构造(比较合理的)正则表达式,使之能够匹配文件中每一行文本。

标准正则                                                         

有两种极端的解法是不可取的:

  1. ^.*$
  2. ^(this is a red fox|this is a blue firefox|this is a pig|a red fox)$

第一种失之于太宽泛,第二种失之于太狭隘。太宽泛则泥沙俱下,无论什么文本都能匹配;太狭隘则僵化死板,缺乏灵活性。好的正则表达式源于例文本(从例文本中提取规律),又高于例文本(能匹配同规律的其它文本)。匹配什么,排除什么,都有定则,所谓“君子有所为而有所不为”,指的就是这种情况(貌似跑题了:))。

那么,如何是比较靠谱的正则表达式呢?以上文的例子而言,可以是:
^(this is )?a (red fox|blue firefox|pig)$

现在我们向着标准答案出发。

思路                                                                       

任何复杂的电路图,都可以拆分为三种简单的关系:串联,并联,短路。正则表达式也同理。

既然是一条正则匹配所有的文本,那么这条正则(记为$re)也应该匹配第一行文本。

第一行文本为this is a red fox。那么,从^this is a red fox$应该是$re的一个(真)子集。它的路径为:“^”->this->is->a->red->fox->”$”。全部节点之间,是串联关系,从左到右依次排列即可。

示意图如下(可以点击看全尺寸图,下同):

Photobucket 

同理,第二行文本也应该是$re的子集。不过,由于已经存在了由^->this->is->a的路径,到a时出现支路,a->blue->firefox->$

将此路径添加到示意图上,得到:

Photobucket 

显而易见,这两条并列的支路,始于a,终于$,可以使用|来并列之。

好了,我们总结一下规律:

并列:如果存在A->B->C,且同时存在A->D->C,则B与D之间是并联关系。即出发点相同,结束点相同,且出发点与结束点之间各有一个以上的节点。并列使用括号来表示,之间以|分隔。例如,对于A->B->C,A->D->C,则可以使用A(B|D)C来表示其正则关系。

为什么要强调是一个以上节点呢?这里先卖个关子。请继续阅读。

再往下,this is a pig,同理,只需要在原图基础上添加a->pig->$的支路即可。此时图示如下:

Photobucket

最后一条,a red fox。这条貌似复杂,但是只需在^->a之间新添加了一条路径而已;a->red->fox->$之间原有路径,可以继续使用。此时,得到完整的示意图如下:

Photobucket 
 此时,观察可知,一种新的情况出现了。同时存在^->a,和“^”->this->is->a两条路径。想一下初中物理电路图,我们可以将这种情况称为“短路”,即,“^”->this->is->a这个线路的^、a两个节点之间,添加了一条无障碍通道,它能无视this、is的存在,因此,让this->is这条路径成为可选项。再总结一下规律:

如果有A->B->…C->D的路径,且有A->D的路径,则称A->D之间存在短路,此时,B->…->C可以用(B->…->C)?来表示(就是用括号来表示被短路的部分,问号表示短路之)。

顶点A,D之间,最多存在一个短路关系。但是可以有1或更多条并列的关系存在。

好了,分析结束,得到这样的正则式:
^(this is )?a (red fox|blue firefox|pig)$

这也就是为什么上文要强调是一个节点的缘故。

如果我们再精益求精的话,可以对red fox|blue firefox|pig这部分递归地进行上述分析过程,进而得到 (red |blue fire)fox|pig这样的结果。

实现                                                                       

思路有了,编程就简单了。perl中,固然可以使用比较简洁的hash表来表示链表之间的关系:
例如:

my $hash;

$$hash{“^”}{“this”}{“is”}{“a”}{“red”}{“fox”}{“\$”}=”";
$$hash{“^”}{“this”}{“is”}{“a”}{“blue”}{“firefox”}{“\$”}=”";

但是,节点的增删修改都是麻烦事。(我在hash迷宫中lost了很久才爬出来)

抽空补了一下有向图的知识,觉得可以简化问题如下。

Photobucket 

上图其实是一个有向图,只需记录所有的顶点集合,路径集合,再来求各路径之间的关系;最后打印输出,即是所求。

顶点集合为:

(^, this, is, a, red, fox, blue, firefox, pig, $);

通路关系集合为:

(^->this, this->is,…)

这两个集合在读取文本文件行的时候可以一次性建立。不复杂。关键是关系的确立。

再次总结,如下:
  • 从一个顶点A出发的N条支路必定汇合(只是有时是同一个点,有时不在同一点而已。本文给出的例子是最简单的情况,这里可以假设为汇合到同一点)于M点。
  • 这N条路中,每一条路径的长短以经过的节点个数来计算。例如上图中,^到a有一条路,上面的路径为2,下面的路径为0。
  • 短的支路决定了这N条支路的关系。
  • 长度为任意两点之间,最多只可能有一条长度为0的边。
  • 如果存在长度为0的边,则其余的同级的支路被短路。
  • 长度不为0的N-1条支路之间是并列关系。
  • 整个图始于^,终于$。
这些条件、判断,均可以细化为函数。具体的程序从略。

个人应用之明文字串到正则

近来工作中需要将某种明文字串转为简单的正则式。手动做当然可以,但是大量重复性的劳动,自然是交给机器处理为好。昨晚写了一款这样的脚本,放在这里。因为是处理我自己的工作的脚本,贴在这里仅作记录和存档之用,可能对别人没什么实际作用。当然,从现有的明文字串到正则式的转换,应该是个不错的题目,有兴趣朋友的可以深究。

值得一提的是,代码中用了$&, (?{}) 这样的perl only的东东,明晰了思路,简化了代码。如果不使用这种特性的话,代码要长5倍。另外,据说从效率上来说,use English之后,使用$MATCH比直接使用$&快5倍。但是对于即输入即执行的命令行程序来说,$&已经足够好。

实际应用一例:

perl hash2re.pl H:aaa-Aaaa-AaaaAaaaaaaAaaaaaaa-AAA0.zip/H:aaa-Aaaa-AaaaAaaaaaaAaaaaaaa-AAA-0/aaa-Aaaa-AaaaAaaaaaaAaaaaaaa-AAA-0/aaa/Aaaaa/aaa-Aaaa-AaaaAaaaaaaAaaaaaaa-AAA-0.exe
RE 1:   ^[a-z]{3}-[A-Z][a-z]{3}-[A-Z][a-z]{3}[A-Z][a-z]{6}[A-Z][a-z]{7}-[A-Z]{3}[0-9]\.zip$
        Matches: "aaa-Aaaa-AaaaAaaaaaaAaaaaaaa-AAA0.zip"
 
RE 2:   ^[a-z]{3}-[A-Z][a-z]{3}-[A-Z][a-z]{3}[A-Z][a-z]{6}[A-Z][a-z]{7}-[A-Z]{3}-[0-9]$
        Matches: "aaa-Aaaa-AaaaAaaaaaaAaaaaaaa-AAA-0"
 
RE 3:   ^[a-z]{3}-[A-Z][a-z]{3}-[A-Z][a-z]{3}[A-Z][a-z]{6}[A-Z][a-z]{7}-[A-Z]{3}-[0-9]$
        Matches: "aaa-Aaaa-AaaaAaaaaaaAaaaaaaa-AAA-0"
 
RE 4:   ^[a-z]{3}$
        Matches: "aaa"
 
RE 5:   ^[A-Z][a-z]{4}$
        Matches: "Aaaaa"
 
RE 6:   ^[a-z]{3}-[A-Z][a-z]{3}-[A-Z][a-z]{3}[A-Z][a-z]{6}[A-Z][a-z]{7}-[A-Z]{3}-[0-9]\.exe$
        Matches: "aaa-Aaaa-AaaaAaaaaaaAaaaaaaa-AAA-0.exe"

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#!/usr/bin/perl
 
#   by rex zhang 
#   Feb 09 2010 in Shanghai
 
#   usage: split and regexize hashed filename
#
 
my $lines=$ARGV[0];
while($lines =~ m#(C:[^/]+)#)
{
    $c=$1;
    $lines =~ s/$c//;
    print "ClearText Filename Ignored:\t\"$c\"\n\n";
 
}
my @array=split(m!\s*(?:\/|H:)+\s*!, $lines); 
 
my $counter=0;
foreach $line (@array){
    next if not $line;
    my $re=$line;
    local $len;    
 
    $re =~ s/(?=[.\[\]()])/\\/g;
    $re =~ s/\?/./g;
    $re =~ s/0+(?{ $len=length($&)})/[0-9]\{$len\}/g; 
    $re =~ s/A+(?{ $len=length($&)})/[A-Z]\{$len\}/g;
    $re =~ s/a+(?{ $len=length($&)})/[a-z]\{$len\}/g;
    $re =~ s/(.)\1+(?{ $len=length($&)})/$1\{$len\}/g;
    $re =~ s/\{1\}//g;
    $re =  "\^$re\$";
 
    $counter++;
    if ($line =~ /$re/)
    {
        print "RE $counter:\t$re\n";
        print "\tMatches: \"$line\"\n";    
    }
    else
    {
        print "RE $counter:\t$re\n";
        print "\tFailed: \"$line\"\n";
    }
    print "\n";
}

统计重复文本行的两种方法

假设样本文件a.txt内容如下:

hello world!
hello world!
I love regex.
hello world!
I love regex.
hello world!

简单观察可知,hello world!共重复4行;I love regex.重复2行。如何使用正则表达式来写一个程序,统计这些数据呢?因为现实中需要统计的文件,绝非是只凭肉眼就能观察出来。我想到了两种方法,第一种方法,是依赖于正则表达式(否则这篇文章也不会贴在这里);第二种,hash表做主角,正则表达式作绿叶。

正则表达式的解法

思路是:对于任何一行文本,如果后面若干行[0~EOF)之后,如果存在相同的文本行,则记下该行内容,统计出现次数;然后删除这样的文本行,再进行下一行的统计。输出统计结果。

下面是相应的perl程序,附注释。

#!/usr/bin/perl 
#usage:  ./dup_re.pl <a.txt
 
undef $/;           # enable "slurp" mode
my $file = <STDIN>;          # whole file now here
 
while($file =~ m
    /                   #for each line;
        ^\s*            #ignore the whitespaces at both ends; 
        (\S.*?)         #get the line content, save to $1;
        \s*$            #ignore empty lines by using \S
        .*?             #check if there is the same pattern of $1
        ^\s*\1\s*$              #after 0 or more lines;
    /smx) 
{
    my $line=$1;                        
    my $count= $file =~ s/$line//g;     #delete the duplicated lines
                       #save the number to $count;
                                       #ignore empty lines
        print $count,"times:\t",$line,"\n";
}

Hash表解法

这种方法,受益于perl语言本身的强大的hash表功能。思路如下:

  • 建立空的hash表;
  • 逐行读取文件;
  • 以文本内容为key,插入到表中来。如果是首次出现,value为0,否则value++。
  • 输出hash表中value>=2的记录。

Perl程序:

#!/usr/bin/perl
#usage:  ./dup_hash.pl a.txt
 
my %hash=();
while(<>)
{
   if (/^\s*(\S.*?)\s*$/)           #ignore whitespaces at both ends; 
   {                                #ignore empty lines by using \S
        $hash{$1}++;                #save the line to $1, and count the time it appears
   }
}
 
#sort the hash by values; 
foreach $key (sort { $hash{$b} <=> $hash{$a} } keys %hash) { 
    if ($hash{$key}>=2)             #only print the lines that duplicates;
    {                               #for all results, just remove the 'if' line
       printf "%d times:\t%s\n", $hash{$key}, $key;
    }
}

结果

上面的程序分别保存为dup_re.pl,dup_hash.pl。由于程序对于外部文件的读取的方法不同,运行方式也有差别,详见下图:
我爱正则表达式|统计重复文本行的两种方法

Update

忽然想到,如果要让这脚本更有效,可以指定忽略大小写,忽略单词间多个空格的情况,使得Hello world!   hello   WORLd! 被视为重复行。测试了一下,正则式没让我失望。

由正则式反推文本:REExtractor

发现一款简单有趣的正则表达式应用:REExtractor,作用是输入正则表达式,输出符合正则式描述的文本。作者给的介绍是
Generate all possibilities of Regular Expression,即生成正则表达式的所有可能性。不过,理论上可以做到,执行时却有限制。

一些限制

  1. 平台是GAE,语言是python,因此用的是python正则。或需代理才能访问使用。
  2. 支持的元字符或缩写:(), [],{m,n},{n},|,\w,\d。如果需要用到这些字符的字面值,请使用反斜线转义之。其中这里的\w等同于[a-zA-Z0-9],为62个字符之一,而不是通常意义上的包括下划线在内的[_a-zA_Z0-9],63字符之一。但是可以用[_\w]来代替,没问题的。
  3. 不支持的元字符:.(点号),^,$,\b,\D,\W,\1…(后向引用), (?=…), (?!…), (?<=…), (?<!…)等。
    • 如果出现.点号,则直接输出。
    • 如果使用^, $, \b, \1, (?=…), (?!…), (?<=…), (?<!…), 程序无视之。
    • 如果使用\D或\b或[^],则程序会报错。原因是范围太宽。
  4. 不支持可能性在1000条以上结果的正则表达式。例如,\w{2},因为它的可能性是62×62。但是你可以使用\w\d,因为它的可能性是62×10。

它能做什么

我爱正则表达式|由正则式反推文本
好吧,虽然限制多多,但是你仍然可以拿它来做一些有趣的应用。下面略举两例。

  • 生成一些简单的邮箱地址。试一下这条正则式:[abc]{3}\d@1(26|63).com ,它生成540条邮箱地址。
  • 生成一些人名。试一下这条正则式:张[小大勇赞强战海][虎猫龙彪平]。它生成35条人名。是的,它支持中文,并且每个中文字都可以当成一个字符来应用。如果你家要添一个宝宝,可以将一些可能的字排列一下,看看哪些组合比较赏心、顺口,再从中选择一个。

平心而论,上面的这些小应用,当然可以直接编程实现,限制更少,更灵活,更强大。但是有必要每次都开编译器么?尝试一下这款小程序,也挺有趣的。而且,上一节中提及的一些限制,其实也是蛮有道理的。毕竟从正则式反推文本,用不到大多数的零宽断言(不过\1这种反向引用应该挺常用的,却不支持)。当作一个小玩具就好。

skydrive外链mp3方案

使用合租空间的独立博客,例如本人,有时想在自己的空间上传mp3,又有版权(美国空间要求趋严)、流量(被迅雷爬到后果很严重)的担心。经过比较,觉得skydrive的空间挺不错的,25G空间,可支持外链。唯一不足之处是操作比较复杂,使用普通的方法不容易批量提取mp3的外链。今天下午做出一种简单易行的方法,可以直接抓取skydrive的公开文件夹里的mp3音乐文件绝对地址并生成Google Player播放代码(因此您就不需要再安装播放mp3的wordpress各种插件了)。所写的php源码一并贴出,有兴趣的自行研究。如果是正则表达式方面的讨论,欢迎跟贴;其它问题恕不回复,见谅。
Read the rest of this entry »

抓取页面图片的单行命令

命令如下:

curl -s $URL |perl -nle "print for m{http://[^\"]+(?:jpg|png|gif)}g;"|sort -u |xargs wget

流程:

  • 将包含图片链接的页面(例如http://www.flickr.com/photos/anyaanja/4165312465/sizes/o/ 下载下来,以便析取图片地址。使用的命令是curl -s $URL。这里的地址需要手动替换为你所需要的地址。curl 的-s选项是表明使用silent模式,避免任何输出。
  • 使用perl解析刚刚下载的页面,找到以http开头,以jpg、png、gif结尾的图片地址。这里的图片类型任意,只要按照类似的语法可以扩展或缩减。perl的-nle选项表示循环读入输入行,搜索相应匹配行,输出相应部分。详细参见perl one liners
  • perl在这里起解析网页的作用。awk应该也有同样的功效,只是个人感觉awk的正则表达式功能太弱较弱。
  • 使用sort -u将生成的url排序。如果有重复项,只保留其一,以免重复下载。
  • 使用wget来下载这些图片到当前目录。由于wget 默认无法接收standard input的输入,因此使用xargs作为中转。

2009120更新:

  • 使用

    curl -s $URL | grep -o "http://.*\?\(png\|jpg\)" |sort -u |xargs wget

    or

    curl -s $URL | grep -E -o "http://.*?(png|jpg)" |sort -u |xargs wget

    能实现同样的作用。其中,-o是表示只显示匹配部分,而不必显示整行文本(默认情况下是显示整行文本);-E 是扩展模式的正则,在此模式下问号、括号、竖线都可直接使用,不必在前边加反斜杠。

  • 使用perl的话,正则表达式部分比较强大,只是命令臃肿;使用grep,灵活小巧,但是有可能无法使用复杂的正则表达式。

使用正则表达式转换手机联系人名单

今天换了手机,第一件要紧事就是恢复联系人名单。旧手机是HTC c720W,新手机是Nokia 5320XM,其联系人名单格式不一。难道要我一条条输入吗?阿弥陀佛,几百组联系人的信息,手动操作会死人的。

我看了一下以前备份的HTC c720W联系人名单,(说到这里,表扬一下自己:勤于备份真是好习惯,万一某天灾难降临,你还有个指望),发现其格式是这样的:


    
      -2147483070
      0
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      SomeBody
      
      1355***9214
      
      

      
      
      
      
      
      
      
      ***
      
      <suffix/>
      <homeaddressstreet/>
      <homeaddresscity/>
      <homeaddressstate/>
      <homeaddresspostalcode/>
      <homeaddresscountry/>
      <otheraddressstreet/>
      <otheraddresscity/>
      <otheraddressstate/>
      <otheraddresspostalcode/>
      <otheraddresscountry/>
      <businessaddressstreet/>
      <businessaddresscity/>
      <businessaddressstate/>
      <businessaddresscountry/>
      <anniversary>1899-12-30 00:00:00</anniversary>
      <birthday>1899-12-30 00:00:00</birthday>
    </item>
    <item>
    ...
    </item>
</contacts>
</pre>
<p>而诺基亚的通讯录格式是这样的:</p>
<pre lang="csv" line="1" colla="-">
"名称","名","中间名","姓","后缀","职务","公司","生日","SIP 地址","一键通","共享视图","用户 ID","备忘","常用手机","常用电话","常用电子邮件","常用传真","常用视频电话","常用网址","常用 VOIP 地址","常用邮政信箱","常用分机","常用街道","常用邮政编码","常用城市","常用省/市/自治区","常用国家/地址","家庭手机","住宅电话","家庭电子邮件","住宅传真","家庭视频电话","家庭网址","家庭 VOIP 地址","家庭邮政信箱","家庭分机","家庭街道","家庭邮政编码","家庭城市","家庭省/市/自治区","家庭国家/地区","公司手机","公司电话","公司电子邮件","公司传真","公司视频电话","公司网址","公司 VOIP 地址","公司邮政信箱","公司分机","公司街道","公司邮政编码","公司城市","公司省/市/自治区","公司国家/地区",""
</pre>
<p>本想偷懒,去找个xml2csv什么的,不过不太好用。还是请“正则表达式”这个老朋友帮忙吧!</p>
<p>分析xml文件,发现只有<br />
mobiletelephonenumber,businesstelephonenumber,hometelephonenumber,firstname,lastname这5个字段是有用的;对应的csv字段名称是:<br />
“名”,”姓”,”常用手机”,”常用电话”,”公司电话”</p>
<p>其余的字段大可放心删除。</p>
<p>祭出RegexBuddy,写了这样一条正则表达式:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
</pre></td><td class="code"><pre class="python" style="font-family:monospace;">result = <span style="color: #dc143c;">re</span>.<span style="color: black;">sub</span><span style="color: black;">(</span>
	r<span style="color: #483d8b;">"""(?smx)(?#"名","姓","常用手机","常用电话","公司电话")
	^<span style="color: #000099; font-weight: bold;">\s</span>*<item>.*?
	<mobiletelephonenumber/?>(?P<mobile>[^<span style="color: #000099; font-weight: bold;">\s</span><]*).*?
	<businesstelephonenumber/?>(?P<business>[^<span style="color: #000099; font-weight: bold;">\s</span><]*).*?
	<hometelephonenumber/?>(?P<home>[^<span style="color: #000099; font-weight: bold;">\s</span><]*).*?
	<firstname/?>(?P<first>[^<span style="color: #000099; font-weight: bold;">\s</span><]*).*?
	<lastname/?>(?P<lastname>[^<span style="color: #000099; font-weight: bold;">\s</span><]*).*?
	</item>"""</span>, 
	r<span style="color: #483d8b;">'"<span style="color: #000099; font-weight: bold;">\g</span><first>","<span style="color: #000099; font-weight: bold;">\g</span><lastname>","<span style="color: #000099; font-weight: bold;">\g</span><mobile>","<span style="color: #000099; font-weight: bold;">\g</span><home>","<span style="color: #000099; font-weight: bold;">\g</span><business>"'</span>, subject<span style="color: black;">)</span></pre></td></tr></table></div>

<p>之所以使用python格式来写正则,是因为它支持命名捕获,看起人直观一些。其实整个替换过程是在RegexBuddy中进行的。</p>
<p>替换后,保存为CSV文件,使用诺基亚自带的软件导入,几百个联系人就又重新归位了。大爽。</p>
<p>附图:<br />
<a href="http://iregex.org/blog/convert-contact-format-from-htc-to-nokia.html"  target="_blank"><img src="http://i293.photobucket.com/albums/mm60/zhasm/iregex/regex_contact_manager.png" border="0" alt="Photobucket"></a><br />
<font color="#ffffff">25f30c5f</font></p>
           </div>

                      <div class="post-tags"><a href="http://iregex.org/blog/tag/csv" rel="tag">csv</a>, <a href="http://iregex.org/blog/tag/xml" rel="tag">xml</a>, <a href="http://iregex.org/blog/tag/%e6%89%8b%e6%9c%ba" rel="tag">手机</a></div>
                           </div>
       <!-- /post -->
       
       <div class="page-navigation" id="pagenavi">
               <div class="wp-pagenavi">
<span class="pages">Page 1 of 1</span><span class="current">1</span></div>
 	          </div>
       
    </div>
    <!-- /primary content -->

    
<div id="sidebar">
 <ul class="sidebar-blocks">

        <li class="block"><div class="block-widget_gajaxsearch" id="instance-google-ajax-search"><h3 class="title"><span></span></h3><div class="block-div"></div><div class="block-div-arrow"></div>                <div id="searchcontrol" width="100%">
                    <form method="get" action="http://blogsearch.google.com/blogsearch ">
                    <input name="as_q" size="16" maxlength="255" value="" type="text">
                    <input name="sa" value="Search" type="submit">
                    <input name="bl_url" value="http://iregex.org" type="hidden">
                    </form>
                </div>
        </div></li><li class="block"><div class="block-widget_text" id="instance-text-315883352"><h3 class="title"><span>Subscribe</span></h3><div class="block-div"></div><div class="block-div-arrow"></div>			<div class="textwidget"><!-- Feedsky FEED发布代码开始 --><!-- FEED自动发现标记开始 --><link title="RSS 2.0" rel="alternate" type="application/rss+xml" href="http://feed.iregex.org" /><!-- FEED自动发现标记结束 -->

<table><tbody>
    <tr>
      <td valign="top"><a target="_blank" href="http://www.zhuaxia.com/add_channel.php?url=http://feed.iregex.org"><img style="margin-bottom: 3px" border="0" alt="抓虾" vspace="2" src="http://img.feedsky.com/images/icon_subshot02_zhuaxia.gif" /></a></td>

      <td valign="top"><a target="_blank" href="http://www.xianguo.com/subscribe.php?url=http://feed.iregex.org"><img style="margin-bottom: 3px" border="0" alt="鲜果" vspace="2" src="http://img.feedsky.com/images/icon_subshot02_xianguo.jpg" /></a><a target="_blank" href="http://www.pageflakes.com/subscribe.aspx?url=http://feed.iregex.org"></a></td>
    </tr>

    <tr>
      <td valign="top"><a target="_blank" href="http://fusion.google.com/add?feedurl=http://feed.iregex.org"><img style="margin-bottom: 3px" border="0" alt="google reader" vspace="2" src="http://img.feedsky.com/images/icon_subshot02_google.gif" /></a></td>

      <td valign="top"><a target="_blank" href="http://add.my.yahoo.com/rss?url=http://feed.iregex.org"><img style="margin-bottom: 3px" border="0" alt="my yahoo" vspace="2" src="http://img.feedsky.com/images/icon_subshot02_yahoo.gif" /></a></td>
    </tr>

    <tr>
      <td valign="top"><a target="_blank" href="http://www.bloglines.com/sub/http://feed.iregex.org"><img style="margin-bottom: 3px" border="0" alt="bloglines" vspace="2" src="http://img.feedsky.com/images/icon_subshot02_bloglines.gif" /></a></td>

      <td valign="top"><a target="_blank" href="http://www.pageflakes.com/subscribe.aspx?url=http://feed.iregex.org"><img style="margin-bottom: 3px" border="0" alt="pageflakes" vspace="2" src="http://img.feedsky.com/images/icon_subshot02_pageflakes.gif" /></a><a target="_blank" href="http://www.xianguo.com/subscribe.php?url=http://feed.iregex.org"></a></td>
    </tr>

    <tr>
      <td valign="top"><a target="_blank" href="http://inezha.com/add?url=http://feed.iregex.org"><img style="margin-bottom: 3px" border="0" alt="哪吒" vspace="2" src="http://img.feedsky.com/images/icon_subshot02_nazha.gif" /></a></td>

      <td valign="top"><a target="_blank" href="http://reader.yodao.com/#url=http://feed.iregex.org"><img style="margin-bottom: 3px" border="0" alt="有道" vspace="2" src="http://img.feedsky.com/images/icon_subshot02_youdao.gif" /></a></td>
    </tr>
  </tbody></table>
<!-- Feedsky FEED发布代码结束 -->
<!-- 以下是统计代码 -->
<script type="text/javascript" src="http://js.tongji.linezing.com/340190/tongji.js"></script><noscript><a href="http://www.linezing.com"><img src="http://img.tongji.linezing.com/340190/tongji.gif"/></a></noscript>
</div>
		</div></li><li class="block"><div class="block-widget_categories" id="instance-categories-2"><h3 class="title"><span>Categories</span></h3><div class="block-div"></div><div class="block-div-arrow"></div>		<ul>
	<li class="cat-item cat-item-6"><a href="http://iregex.org/blog/category/books" title="View all posts filed under 书籍">书籍</a> (4)
</li>
	<li class="cat-item cat-item-71 current-cat"><a href="http://iregex.org/blog/category/%e5%ba%94%e7%94%a8" title="View all posts filed under 应用">应用</a> (7)
</li>
	<li class="cat-item cat-item-7"><a href="http://iregex.org/blog/category/tutorial" title="View all posts filed under 教程">教程</a> (17)
</li>
	<li class="cat-item cat-item-4"><a href="http://iregex.org/blog/category/news" title="View all posts filed under 新闻">新闻</a> (3)
</li>
	<li class="cat-item cat-item-1"><a href="http://iregex.org/blog/category/miscellaneous" title="View all posts filed under 杂项">杂项</a> (11)
</li>
	<li class="cat-item cat-item-59"><a href="http://iregex.org/blog/category/%e7%bf%bb%e8%af%91" title="View all posts filed under 翻译">翻译</a> (4)
</li>
	<li class="cat-item cat-item-38"><a href="http://iregex.org/blog/category/software" title="View all posts filed under 软件">软件</a> (11)
</li>
	<li class="cat-item cat-item-5"><a href="http://iregex.org/blog/category/qa" title="View all posts filed under 问答">问答</a> (4)
</li>
		</ul>
</div></li><li class="block"><div class="block-widget_tag_cloud" id="instance-tag_cloud-3"><h3 class="title"><span>Tag Cloud</span></h3><div class="block-div"></div><div class="block-div-arrow"></div><div><a href='http://iregex.org/blog/tag/tutorial' class='tag-link-7' title='2 topics' style='font-size: 11.1111111111pt;'>教程</a>
<a href='http://iregex.org/blog/tag/%e6%ad%a3%e5%88%99%e5%bc%8f' class='tag-link-49' title='4 topics' style='font-size: 14.9135802469pt;'>正则式</a>
<a href='http://iregex.org/blog/tag/%e6%ad%a3%e5%88%99%e8%a1%a8%e8%be%be%e5%bc%8f' class='tag-link-50' title='4 topics' style='font-size: 14.9135802469pt;'>正则表达式</a>
<a href='http://iregex.org/blog/tag/software' class='tag-link-38' title='3 topics' style='font-size: 13.1851851852pt;'>软件</a>
<a href='http://iregex.org/blog/tag/%e9%be%99%e4%b9%a6' class='tag-link-78' title='2 topics' style='font-size: 11.1111111111pt;'>龙书</a>
<a href='http://iregex.org/blog/tag/adobe' class='tag-link-52' title='1 topic' style='font-size: 8pt;'>Adobe</a>
<a href='http://iregex.org/blog/tag/asp' class='tag-link-9' title='1 topic' style='font-size: 8pt;'>asp</a>
<a href='http://iregex.org/blog/tag/cheatsheet' class='tag-link-10' title='1 topic' style='font-size: 8pt;'>cheatsheet</a>
<a href='http://iregex.org/blog/tag/chinese' class='tag-link-11' title='5 topics' style='font-size: 16.2962962963pt;'>chinese</a>
<a href='http://iregex.org/blog/tag/chm' class='tag-link-12' title='1 topic' style='font-size: 8pt;'>chm</a>
<a href='http://iregex.org/blog/tag/curl' class='tag-link-56' title='3 topics' style='font-size: 13.1851851852pt;'>curl</a>
<a href='http://iregex.org/blog/tag/dfa' class='tag-link-76' title='3 topics' style='font-size: 13.1851851852pt;'>DFA</a>
<a href='http://iregex.org/blog/tag/download' class='tag-link-13' title='1 topic' style='font-size: 8pt;'>download</a>
<a href='http://iregex.org/blog/tag/dreamweaver' class='tag-link-14' title='1 topic' style='font-size: 8pt;'>dreamweaver</a>
<a href='http://iregex.org/blog/tag/earthquake' class='tag-link-15' title='1 topic' style='font-size: 8pt;'>earthquake</a>
<a href='http://iregex.org/blog/tag/ebook' class='tag-link-16' title='1 topic' style='font-size: 8pt;'>ebook</a>
<a href='http://iregex.org/blog/tag/excel' class='tag-link-17' title='1 topic' style='font-size: 8pt;'>excel</a>
<a href='http://iregex.org/blog/tag/expresso' class='tag-link-18' title='2 topics' style='font-size: 11.1111111111pt;'>expresso</a>
<a href='http://iregex.org/blog/tag/fanfou' class='tag-link-19' title='4 topics' style='font-size: 14.9135802469pt;'>fanfou</a>
<a href='http://iregex.org/blog/tag/firefox' class='tag-link-20' title='2 topics' style='font-size: 11.1111111111pt;'>firefox</a>
<a href='http://iregex.org/blog/tag/geshi' class='tag-link-21' title='1 topic' style='font-size: 8pt;'>geshi</a>
<a href='http://iregex.org/blog/tag/google' class='tag-link-3' title='2 topics' style='font-size: 11.1111111111pt;'>google</a>
<a href='http://iregex.org/blog/tag/grep' class='tag-link-60' title='2 topics' style='font-size: 11.1111111111pt;'>grep</a>
<a href='http://iregex.org/blog/tag/just-great-software' class='tag-link-22' title='2 topics' style='font-size: 11.1111111111pt;'>just great software</a>
<a href='http://iregex.org/blog/tag/languages' class='tag-link-23' title='1 topic' style='font-size: 8pt;'>languages</a>
<a href='http://iregex.org/blog/tag/mtracer' class='tag-link-24' title='1 topic' style='font-size: 8pt;'>mtracer</a>
<a href='http://iregex.org/blog/tag/newbie' class='tag-link-25' title='2 topics' style='font-size: 11.1111111111pt;'>newbie</a>
<a href='http://iregex.org/blog/tag/nfa' class='tag-link-75' title='3 topics' style='font-size: 13.1851851852pt;'>NFA</a>
<a href='http://iregex.org/blog/tag/pdf' class='tag-link-26' title='5 topics' style='font-size: 16.2962962963pt;'>pdf</a>
<a href='http://iregex.org/blog/tag/perl' class='tag-link-27' title='9 topics' style='font-size: 20.0987654321pt;'>perl</a>
<a href='http://iregex.org/blog/tag/php' class='tag-link-28' title='2 topics' style='font-size: 11.1111111111pt;'>php</a>
<a href='http://iregex.org/blog/tag/plugin' class='tag-link-29' title='1 topic' style='font-size: 8pt;'>plugin</a>
<a href='http://iregex.org/blog/tag/powergrep' class='tag-link-30' title='5 topics' style='font-size: 16.2962962963pt;'>powergrep</a>
<a href='http://iregex.org/blog/tag/project-babel' class='tag-link-31' title='1 topic' style='font-size: 8pt;'>project babel</a>
<a href='http://iregex.org/blog/tag/python' class='tag-link-32' title='7 topics' style='font-size: 18.3703703704pt;'>python</a>
<a href='http://iregex.org/blog/tag/recursive' class='tag-link-90' title='2 topics' style='font-size: 11.1111111111pt;'>recursive</a>
<a href='http://iregex.org/blog/tag/regex' class='tag-link-34' title='12 topics' style='font-size: 22pt;'>regex</a>
<a href='http://iregex.org/blog/tag/regexbuddy' class='tag-link-35' title='9 topics' style='font-size: 20.0987654321pt;'>regexbuddy</a>
<a href='http://iregex.org/blog/tag/regexguru' class='tag-link-57' title='2 topics' style='font-size: 11.1111111111pt;'>regexguru</a>
<a href='http://iregex.org/blog/tag/tool' class='tag-link-40' title='5 topics' style='font-size: 16.2962962963pt;'>tool</a>
<a href='http://iregex.org/blog/tag/translation' class='tag-link-41' title='3 topics' style='font-size: 13.1851851852pt;'>translation</a>
<a href='http://iregex.org/blog/tag/url' class='tag-link-43' title='2 topics' style='font-size: 11.1111111111pt;'>url</a>
<a href='http://iregex.org/blog/tag/utf8' class='tag-link-44' title='3 topics' style='font-size: 13.1851851852pt;'>utf8</a>
<a href='http://iregex.org/blog/tag/xml' class='tag-link-47' title='4 topics' style='font-size: 14.9135802469pt;'>xml</a>
<a href='http://iregex.org/blog/tag/xpath' class='tag-link-48' title='2 topics' style='font-size: 11.1111111111pt;'>xpath</a></div>
</div></li>		<li class="block"><div class="block-widget_recent_comments" id="instance-recent-comments-3">			<h3 class="title"><span>Comments</span></h3><div class="block-div"></div><div class="block-div-arrow"></div>			<ul id="recentcomments"><li class="recentcomments"><a href="http://timecube.limewebs.com/" onclick="javascript:pageTracker._trackPageview('/outbound/commentauthor/timecube.limewebs.com');"  rel='external nofollow' class='url'>小轰</a> on <a href="http://iregex.org/blog/wordpress-word-counter-for-utf8-chinese.html/comment-page-1#comment-2986">wordpress UTF8 中文字数统计插件</a></li><li class="recentcomments"><a href="http://timecube.limewebs.com/" onclick="javascript:pageTracker._trackPageview('/outbound/commentauthor/timecube.limewebs.com');"  rel='external nofollow' class='url'>小轰</a> on <a href="http://iregex.org/blog/wordpress-word-counter-for-utf8-chinese.html/comment-page-1#comment-2985">wordpress UTF8 中文字数统计插件</a></li><li class="recentcomments">smy20011 on <a href="http://iregex.org/blog/text-2-regular-expressions-again.html/comment-page-1#comment-2976">关于从普通文本提取正则表达式的再思考</a></li><li class="recentcomments">tanktang on <a href="http://iregex.org/blog/mastering-regular-expressions-vedio-tutorial-download.html/comment-page-1#comment-2970">《精通正则表达式》视频教程提供下载</a></li><li class="recentcomments">tanktang on <a href="http://iregex.org/about/comment-page-1#comment-2969">About</a></li><li class="recentcomments">乘风 on <a href="http://iregex.org/blog/mastering-regular-expressions-vedio-tutorial-download.html/comment-page-1#comment-2764">《精通正则表达式》视频教程提供下载</a></li><li class="recentcomments">rex on <a href="http://iregex.org/blog/regular-expressions-in-emeditor.html/comment-page-1#comment-2742">EmEditor中的正则表达式</a></li><li class="recentcomments"><a href="http://my.opera.com/jlake/blog/" onclick="javascript:pageTracker._trackPageview('/outbound/commentauthor/my.opera.com');"  rel='external nofollow' class='url'>jlake</a> on <a href="http://iregex.org/blog/regular-expressions-in-emeditor.html/comment-page-1#comment-2741">EmEditor中的正则表达式</a></li></ul>
		</div></li><li class="block"><div class="block-widget_links" id="linkcat-2"><h3 class="title"><span>Blogroll</span></h3><div class="block-div"></div><div class="block-div-arrow"></div>
	<ul class='xoxo blogroll'>
<li><a href="http://anrs.sacredfir.com/" rel="friend" onclick="javascript:pageTracker._trackPageview('/outbound/blogroll/anrs.sacredfir.com');" title="Regex/Python/Django/Ubuntu/Emacs" target="_blank">Anrs Hu</a></li>
<li><a href="http://chunzi.me/" rel="friend co-worker" onclick="javascript:pageTracker._trackPageview('/outbound/blogroll/chunzi.me');" title="less is more (?# #perl #git #vim)" target="_blank">chunzi.me</a></li>
<li><a href="http://www.luanxiang.org/blog/" rel="" onclick="javascript:pageTracker._trackPageview('/outbound/blogroll/www.luanxiang.org');" title="《精通正则表达式》中文第三版译者余晟先生博客" target="_blank">乱象,印迹</a></li>
<li><a href="http://zhasm.com" rel="" onclick="javascript:pageTracker._trackPageview('/outbound/blogroll/zhasm.com');" title="表达意见情感,分享经验心得" target="_blank">深柳堂</a></li>
<li><a href="http://zhiqiang.org/blog/" rel="" onclick="javascript:pageTracker._trackPageview('/outbound/blogroll/zhiqiang.org');" title="科学论述文章(以理论计算机和数学为主),书评及时政经济评论。" target="_blank">阅微堂</a></li>

	</ul>
</div></li>


 </ul>
</div>

    <div class="clear"></div>

   </div>
  </div>
  <!-- /main content -->

 <!-- foooter -->
  <div id="footer">

 


   <div class="page-content">
    <div id="copyright">

     Mystique theme by <a href="http://digitalnature.ro">digitalnature</a> | Powered by <a href="http://wordpress.org/">WordPress</a> <br /> <a class="rss-subscribe" href="http://iregex.org/feed" title="RSS Feeds">RSS Feeds</a> <a class="valid-xhtml" href="http://validator.w3.org/check?uri=referer" title="Valid XHTML">XHTML 1.1</a> <a id="goTop" class="js-link">TOP</a>     
    </div>
   </div>
  </div>
  <!-- /footer -->

 </div>
</div>
<!-- /shadow -->

  
  <script type='text/javascript' src='http://iregex.org/wp-content/themes/mystique/js/jquery.mystique.min.js?ver=2.9.2'></script>

  <script type="text/javascript">
  /* <![CDATA[ */
    var isIE6 = false; /* <- do not change! */
    var isIE = false; /* <- do not change! */
  /* ]]> */
  </script>
  <!--[if lte IE 6]> <script type="text/javascript"> isIE6 = true; isIE = true; </script> <![endif]-->
  <!--[if gte IE 7]> <script type="text/javascript"> isIE = true; </script> <![endif]-->

  <!--[if lte IE 7]>
   <div class="crap-browser-warning">You're using a old and buggy browser. Switch to a <a href="www.mozilla.com/firefox/">normal browser</a> or consider <a href="http://www.microsoft.com/windows/internet-explorer/">upgrading your Internet Explorer</a> to the latest version</div>
  <![endif]-->

  <!-- 125 queries. 0.604 seconds. -->
 </div>
</body>
</html>