总结在 python 语言里使用正则表达式匹配中文的经验。关键词:中文,cjk,utf8,unicode,python。
浏览CU时发现Superor老师的《探索Perl的世界(更新到40集)-Perl 教学视频》(国人,中文),其中有5集是讲正则表达式的。观看之后觉得不错,贴在这里。 Read more…
网友cfc4n问及关于(?!)的正则表达式问题。回答之后,顺便总结了一下Perl语言中如何匹配“不出现”某元素,贴在这里。 Read more…
其实RegexBuddy挺好用的,我一直用它。它的用法、好处,可以写好多文字,本站也做过介绍;不过,也有理由不用它,同时这也是撰写本文的一个原因。我动了动脑筋,花了一点时间,已经做出雏形。现在将思路公布在这里,与各位交流一下。
之前一篇文章翻译了Perl语言中的递归正则表达式. 其实不少语言中的正则都是支持递归的, 例如本文要介绍的PHP正则递归. 虽然, 工作中最常用的正则表达式都很”正则”, 只用最基本的语法就能解决85%以上的问题, 而且合理有效地使用普通正则来解决复杂问题也是一门技巧与学问; 但是高级一点的语法的确有它存的价值, 有时不用它还真办不了事儿; 况且学习正则的乐趣也在于尝试各种各样的可能性, 满足自己无穷无尽的好奇心.
本文内容, 整理自网文Finer points of PHP regular expressions. 其分析过程剥茧抽丝, 丝丝入扣, 值得一读. 该文系统地列出了PHP中正则表达式常见特性, 我只摘取其中递归部分翻译整理出来.
原空间(homezz.com)到期, 顺便换为法国alwaysdata.com的了. 搬家很顺利, 使用scp将数据从原空间隔空传物过去; 配置好域名dns, 数据文件, 新空间就激活了. 很顺利.
另, 新站的访问速度如何? 可以接受吗?
目前在蕴酿一篇关于”如何DIY一款像RegexBuddy那样的正则表达式工具”的博客, 敬请期待.
问题
以下摘自某网友来信:
难点
见chinaunix论坛上有这样一问:
搜索重复单词(“this this”)问题,问为什么第4行要加^:
1 2 3 4 5 6 7 | $/ = ".\n"; while (<>) { next if !s/\b([a-z]+)((?:\s< <[^>]+>)+)(\1\b)/\e[7m$1\e[m$2\e[7m$3\e[m/ig; s/^(?:[^\e]*\n)+//mg; # Remove any unmarked lines. # 为何需要加^ s/^/$ARGV: /mg; # Ensure lines begin with filename. print; } |
要解答这个问题,不能只print "hello world";着眼于这一行。程序不长,从头到尾详细读一下,这个问题就兵不血刃地解决了。 Read more…
这两天写了一段perl程序,输入url地址,下载其中的文件,计算MD5值,查该文件是否是病毒;如果无记录,则调用另外一个perl脚本将其上传到某一网站作详细测试。我想说的是,这些功能可能使用bash来编程,会更直接;用perl来做bash的事情总有些越俎代庖。不过,目前我对perl极感兴趣;有机会就用它;另外,将不成熟的代码贴出来,留给未来的自己一个鄙视现在的自己的机会也好:)
一个小小的发现是,qx可以将所包含的语句当作bash命令来执行,并把结果返回。另外书中交待,eval也是极有用的,不过这次没用上,下次找机会牛刀小试一把。
之所以没有使用curl, md5等等模块,而是使用shell命令,是因为我所用的虚拟机里没有安装,但是它们是bash下标准的可执行文件。这样写来,效率会有点折扣,但是绿色便携。
无废话,贴代码。
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 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | #!/usr/bin/perl -w #this script offers a better download service #integreting virustotal infor, send-sample.pl #by rex.zhang #on 03-11-2010 in Shanghai #updated @003122010; my ($url)=$ARGV[0]; #it is assumed that the filename is the last part of the url, #just after the last / and before the $ main($url); sub main { my ($url)=@_; #print help message and quit if no url input; help() if (not $url); my ($md5,$size,$name); $url =~ /\/([^\/]+)$/; #get the filename from the url; $name=$1; #get filesize from the url; if no size got, quit. $size=get_filesize($url); exit if $size; #try 5 times at most to get the file. my ($try)=5; my $ok; while($try--) { $ok=download_file($url); last if $ok; } if (not $ok) { print "can not download the file, quit!\n"; exit(); } #get the md5 locally $md5=get_md5($name); #and the url link from $virustotal; my ($link)=get_vt_link($md5); if ($link) { #and even the virus infor; my ($info)=get_vt_info($link); if (not $info) { v_test($name,$md5); print "\nSample has been sent to vtest. \nthanks for using.\n\n"; } } } #return the md5 value of the file. #the filename is in the current directory sub get_md5 { my ($filename)=@_; my $md5=`md5sum $filename`; $md5 =~ /^(\w{32})/; print "\nthe md5 of the $filename is:\t $1.\n"; return $1; } #get the virustotal link with the given md5 value; sub get_vt_link { my($md5)=@_; my ($link)=`curl -s -e "https://www.virustotal.com" -d "x=80&y=23&hash=$md5" "http://www.virustotal.com/vt/en/consultamd5" | grep href`; my ($bool)= $link =~ /href="([^"]+)"/i; if ($bool) { return "http://www.virustotal.com".$1; } else { return 0; } } #get the virus infor according to a virus total infor link sub get_vt_info { my($url)=@_; my $line; my $sophos =0; #if sophos has no detection, do the vtest. foreach (qx{curl -s $url}) { $line.=$_; } my (@result) = $line=~ m!<tr[^>]*>\s*<td>(?:Sophos|Symantec|TrendMicro|McAfee)</td>.*?</tr>!sig; if (not @result) { print "\nNo record in VirusTotal. Sending v-test...\n"; return $sophos; } print "\nvirustotal record found as following:\n"; foreach (@result) { my $tmp=$_; $tmp =~ s/(<[^>]+>\s*)+/\t/sig; print $tmp."\n"; if ($tmp =~ m/(?:Sophos[.\s0-9]+)(?!-)(\S+)\s*$/i) { $sophos=$1; } } print "\nSophos has detection as $sophos, no v-test needed.\n" if $sophos; print "you can read the virus details here:\n"; print "\t$url\n\n"; exit() if $sophos; } #get the filesize by using the curl -I option. #print the filesize if it is greater than a given value, 2MB by default. sub get_filesize{ my ($url)=@_; my ($size,$unit); foreach (qx{curl -s -I $url}) { if (/Content-Length:\s(\d+)/) { $size=$1; } if (/Accept-Ranges:\s(\w+)/) { $unit=$1; } } if (not $size) { print "can not get the length of the file, exit!\n"; exit; } $size=int($size / 1024); my $flag=0; #if flag=1 it is too large ; if ($size>1024 * 2) { $flag=1; print "the file is ${size}KB and greater than 2MB!\n"; print "it is too large to be a virus. exit.\n"; } else { print "\nThe file size is $size kb, downloading...\n\n"; } $flag; } #simply download the file sub download_file { my ($url)=@_; $url =~ /([^\/]+)$/; my $filename=$1; `curl -O $url`; if (not -e $filename) { print "no filename, retrying...\n"; return 0; } print "\nfile is downloaded and saved as $filename.\n"; 1; } #print the help message and exit if no url input sub help { print "Usage: ./dl http://.../file.exe\n"; print "\tthe last part of the url is regarded as filename.\n"; exit(); } #send the v-test email, with md5 value in the subject. sub v_test { my ($file,$md5)=@_; `zip $file.zip $file`; `send-sample.pl -a $file.zip -s "$file.zip URL MD5 $md5"`; } |
rex按:
写完上一篇文章之后,一直在考虑如何真正实现从普通文本中归纳正则表达式的实现。走了许多弯路,也学了不少知识。例如,perl黑豹书上复杂的数据结构、匿名散列和数组、refenrence;紫龙书上的状态机的构造,数据结构上图论的知识,都是很有用的。另外还新学了graphviz的用法。以前觉得很神秘,不过一用才发现很直观。本文的插图是使用online版本的graphviz画的。
除了本文的这种实现方法(基于图),我还使用另一种方式实现了,很简单:基于关键词。具体作法是,逐一读取每一行文本,使用\s+等将其split开,形成array;然后再对所有的array进行求交集的操作(使用hash),得到每一行都有的关键词;然后按从左到右的顺序建立这覆的正则式^(.*?)keyword1(.*?)keyword2….keywordN(.*?)$,再分别匹配每一行文本,得到hash的hash表,或者array的array,转置,并列输出,得到^(option1|option2…)keyword1(option..)…$这样的正则式。最后作为验证,再将所最终生成的正则与每一行匹配测试一下。
这样以词为单位做完之后,再逐个字母地分隔开来,递归地处理(option1|option2…)的部分。先是单词级,再是字母级,有利于先在最大程度上找出重复的内容;而且粗化和细化的处理过程,思路是一致的,粒度不同罢了。
新手请自重,高手请赐教,我的思路未必是正确或最优的。
近来工作中需要将某种明文字串转为简单的正则式。手动做当然可以,但是大量重复性的劳动,自然是交给机器处理为好。昨晚写了一款这样的脚本,放在这里。因为是处理我自己的工作的脚本,贴在这里仅作记录和存档之用,可能对别人没什么实际作用。当然,从现有的明文字串到正则式的转换,应该是个不错的题目,有兴趣朋友的可以深究。
值得一提的是,代码中用了$&, (?{}) 这样的perl only的东东,明晰了思路,简化了代码。如果不使用这种特性的话,代码要长5倍。另外,据说从效率上来说,use English之后,使用$MATCH比直接使用$&快5倍。但是对于即输入即执行的命令行程序来说,$&已经足够好。
假设样本文件a.txt内容如下:
1 2 3 4 5 6 | hello world! hello world! I love regex. hello world! I love regex. hello world! |
简单观察可知,hello world!共重复4行;I love regex.重复2行。如何使用正则表达式来写一个程序,统计这些数据呢?因为现实中需要统计的文件,绝非是只凭肉眼就能观察出来。我想到了两种方法,第一种方法,是依赖于正则表达式(否则这篇文章也不会贴在这里);第二种,hash表做主角,正则表达式作绿叶。 Read more…

