perl语言的优势在于语法灵活,正则表达式强大。它的缺点其实也在于语法过于灵活,正则强大而复杂。但是用来文本处理工具还是很不错的工具。
最近翻了一下《精通正则表达式》,看到几个强大而实用的正则表达式用法:
1. 利用 正则中的 环视 操作符来为数字添加分割逗号,例如:35,738,480
$num = 35738480;
$num =~ s!(?<=/d)(?=(/d/d/d)+$)!,!g
#这个式子主要可以用在统计邮件中
2. 利用perl的动态正则表达式进行 嵌套tag的匹配
问题: 匹配 标红部分:
<div>
<div><table><div>AA</div></table></div> <div>BB</div>
<div>CC</div>
<div><table>DD</table></div>
</div>
之前自己想到的一种解法:普通正则表达式 匹配两层tag嵌套:
$str='<div>
<div><table><div>AA</div></table></div> <div>BB</div>
<div>CC</div>
<div><table>DD</table></div>
</div>
';
$str =~ m!<div>(.*?(?:<div>.*?(?:<div>.*?</div>.*?)*</div>.*?)*)</div>!xs;
print "$1/n";
其中(?:)表示不用于捕获的分组,末尾的x表示宽松排列允许正则中包含空格和注释,末尾的s表示点号通配符匹配换行。m!!是perl语言的正则匹配语法。
但是这种方法只能匹配最多两层的<div></div>的标签嵌套。
实际上使用perl特有的功能,动态正则表达式可以实现匹配多层的标签嵌套(当然用自己用栈或者别的方式也可以实现,这里只涉及正则)。
#首先先声明一个嵌套结构
my $levelN;
$levelN = qr!.*?<div>(?:.*?|(??{$levelN}))</div>.*?!xs;
#应用这个嵌套结构
$str =~ m!<div>(.*?(?:$levelN)*)</div>!xs
print "$1/n";
3. 利用perl的命令行接口代替grep和sed
问题:从页面中提取符合模式的 url 并转换为有效形式
页面中的url形式:<a href="/f421">
转换为:输出 http://bbs.kaoyan.com/f421p1
实现这个功能实际只需要一行代码
perl -n -e 'm/"//(f/d+)"/;print "http://bbs.kaoyan.com/$1p1/n"' index.html|sort -u
这个脚本实现从index.html页面中获取论坛的频道url的功能。
其中-n 表示对文件中每一行进行处理 -e后面接上perl脚本,最后重定向到sort进行排重。个人觉得这个比grep+sed要直观好用,并且可以利用到perl语言强大的正则功能。
Perl命令行参数:
-0< 数字> (用8进制表示)指定记录分隔符($/变量),默认为换行
-00 段落模式,即以连续换行为分隔符
-0777 禁用分隔符,即将整个文件作为一个记录
-a 自动分隔模式,用空格分隔$_并保存到@F中。相当于 @F = split ”。分隔符可以使用-F参数指定
-F 指定-a的分隔符,可以使用正则表达式
-e 执行指定的脚本。
-i< 扩展名> 原地替换文件,并将旧文件用指定的扩展名备份。不指定扩展名则不备份。
-l 对输入内容自动chomp,对输出内容自动添加换行
-n 自动循环,相当于 while(<>) { 脚本; }
-p 自动循环+自动输出,相当于 while(<>) { 脚本; print; }