一定有人还记得在dos和Unix下面的这些命令
$ls-limg1?.jpg
dir*.exe
这里的星号通配符和问号通配符就是正则表达式符号确切地说是Dosshell和Unixshell使用的正则表达式符号Perl的正则表达式规则与这两些shell的都有所不同但Perl的正则表达式影响最大几乎成了业界标准以至于近年来新建的一些计算机语言都要申明自己实现了Pcre(Perl兼容的正则表达式要不然都不好意思出来混江湖(微软除外)
Perl正则表达式的使用很简单(其实实现起来很难)跟我来
1.Perl正则表达式相关的操作符
先不说正则表达式本身下面我们的正则表达式就用apple.先定义一个字符串
my$szProductType=applecider;
现在要检验它里面有没有字符串apple
if($szProductType=~/apple/){
print$szProductType.\n;
}
上面的=~要看做一个符号是Perl的正则表达式匹配操作符这个符号匹配成功返回1否则返回0后面的两个/之间包括的就是正则表达式这是就是apple正则表达式也可以不用/符号而改用其它符号包括鉴于海马一向厌恶这种标新立异做无用功的行为就不说怎么操作了偏执到不喜欢/符号的人请自己去查Perl手册吧如果要求匹配一个字符串里面没有apple怎么办当然可以这样(花括号里该写什么自己写吧我省略啦)
unless($szProductType=~/apple/){}
还可以这样
if(!($szProductType=~/apple/)){}
但是为了表示你很懂Perl,你应该这样这也是我最喜欢的方式画外音这和前面那个被批判的标新立异有啥区别嗯使用不匹配操作符号!~
if($szProductType!~/apple/)){}
最后为了避免被人看穿自己很不懂Perl看到下面的表达式的时候千万不要露怯
if($szProductType!~m/apple/)){}
这个m是干什么的答案是这个地方有m没m一样的都是表示匹配(match)请直接无视之对于匹配操作符也是一样的情况
2.Perl正则表达式语法
所谓正则表达式就是一串特别设计过的字符串可以按照你的意图用匹配操作寻找你要求的目标我这里不是Perl手册也不是教科书所以我从例子开始具体的完整说明还请查手册
2.1转义符号\
前面说过缺省情况下正则表达式要用/包起来那么现在要寻找一个字符串里面有没有/怎么办不是有歧义了么那个表达式换你设计Perl语言该咋办玩过C语言的人看到这里一定在嘿嘿笑因为在C里面简单要写/必须写成\/要写\必须写成\\说Perl在语法上是C的表弟是很不错的Perl规定的转义符号也是\.常用的特殊符号有回车\n,跳格\t,斜杠\\和\/引号\和\方括号\[和\]圆括号\(和\)美元号\$上尖号\^星号\*点号\.问号\?加号\+我都是随手写的建议拿不定主意的话非52个字母的符号都去查查手册吧举例查一个字符串里有没有美元号
my$szValue=$6580.90;
$szValue=~/\$/;
2.2或操作
Perl的正则表达式缺省是区别大小写的什么前面早该告诉你真可怜又一个从Windows世界来的小孩就和我想当然以为在美国商店应该在复活节大做生意创造GDP一样可是人家不开门为了串即匹配Apple又匹配apple你可以这样
$szProductType=~/[Aa]pple/;
在方括号里的字母是或的关系击中其中一个就可以了在一个正则表达式中可以用任意多个方括号但是不要嵌套常常能见到的一种表达式
[0-9]
表示0到9这十个字母也可以用\d来代替\D则表示非数字字符
[a-zA-Z]
表示52个字母
顺便在这里把反义也讲了吧[^0-9]代表非数字的其它字符[^a]代表非a的其它字符^在这里是反义的意思但是请注意^还能做头锚用后面会讲到
2.3尾缀
有人摇头不喜欢上面的解决方案我要求真正匹配一个不区分大小写的Apple应该怎么办请这样
$szProductType=~/apple/i;
放在第二个/符号后面的尾缀i取消了一切大小写检查
另外再说两个有用的尾缀吧第一个是g全局匹配如果有字符串
my$string=Applejuice,appleCider,applejeans,applepie,appleplate,apPLebag,;
而用表达式$string=~/apple/i只会遇到第一个apple就结束现在我们可以用尾缀g配合while循环
while($string=~/(apple.*?),/ig){
print$1\n;
}
就可以找出所有带apple的词汇注意尾缀是可以叠加使用的上面正则表达式中的圆括号点号和问号和$1下面马上会讲到
另一个有用的的尾缀是ss会强迫点号(.)匹配换行符号(\n)这对于多行匹配是必须的不要小看这个技巧我花了几个小时才找到的哦
2.4捕获匹配的字符串
my$szValue=$1999.99;
if($szValue=~/\$([0-9]+)\.([0-9]+)/){
print$1dollors$2cents\n;
}
上面表达式里的加号表示匹配一到多个前面的符号在这里符号是数字用圆括号括住的内容将会依次从左到右出现在$1,$2,$3里面另外顺便说整个正则表达式匹配的结果是放在$里面上面这个表达式演算下来$的值还是$1999.99
另外还有\1,\2形式的反向引用使得表达式里面可以用捕获的字符串举例表达式(\w)\1{4,}在匹配aabbbbabcdefgccccc111121111999999999时匹配结果是成功匹配到的内容是ccccc再次匹配下一个时将得到999999999(要用while和/g来配合
2.5任意符号.和次数符号*以及+
Perl正则表达式里点号是通配任意字母的例如
$string=~/w.*/i;
就匹配$string里从第一个w字母开始一直到字符串结束*表示匹配任意字母0到任意多次*号也常被换成+号表示匹配1到任意多次如果即没有*也没有+那么就是匹配1次如果要自己定义匹配的次数或者次数上下限怎么办用{}符号
$string=~/\d{5,15}/;
上面的式子匹配5到15位数字
$string=~/\d{20}/;
上面的式子匹配20位数字
附带说两个常用的符号\S和\s前者是非空白后者是空白具体来说包括回车空格跳格响铃
2.6贪婪的+和*止贪剂?
Perl的正则表达式是贪婪的(确切地说次数符号+和*是贪婪的)可以帮助你做一些事情
my$string=$290098;
$string=~/\$(\d+)/;
由于+号的贪婪性$1会得到值290098而不是遇到第一个数字2就完成匹配
但有的时候你会不希望他贪婪希望见好就收还是我前面用过的一个例子
my$string=Applejuice,appleCider,applejeans,applepie,appleplate,apPLebag,;
如果用
$string=~/(apple.*),/i;
由于*的贪婪性它会一直匹配到最后一个逗号才停下来这不是我们想要的结果解决办法是用止贪符号?紧跟在*或者+后面
$string=~/(apple.*?),/i;
问号会约束*遇到第一个逗号就停下来
2.6头锚^和尾锚$
有时候你希望从一个字符串的开始或者结尾匹配
my$string=Aquickbrownfoxjumpsoveralazysnake;
$string=~/^A/;#匹配第一个字母是否为A
$string=~/snake$/;#匹配最后几个字母是否为snake
还有一个\b匹配的是单词边界意思是空白或者开头或者结尾
3.其它相关函数及注意事项
3.1替换功能和quotemeta
有时候你不仅希望找到你想要那些字符串还想替换掉它们还记得前面说的匹配符后面的m符号么现在是使用另一个s符号(替换subplace)的时候了
$string=~s/apple/apple/i;
上面表达式将$string里所有不用形式的apple统一成全小写的apple.这里面可以用变量
$string=~s/$string1/$string2/i;
$string里所有匹配$string1的地方都会被替换成$string2但是要注意除非你能确保$string1里面不含任何特殊符号(+-*^$.()[]等)或者你需要的就是那些符号最好在调用上面式子之前处理一下$string1
$string1=quotemeta($string1);
quotemeta()的作用是给字符串里的特殊符号加上合适的转义符号注意不需要给$string2做这个处理
3.2不要在while里改变字符串
还记得2.3里面的while循环么警告不要在while循环里改变$string的值否则可能会陷入无限循环如果你真得这样做把$string复制一次一个镜像用来循环一个用来做替换
3.3study及提高性能
有很多人想了很多种办法来提高Perl正则表达式的性能我一概记不住如果你要处理的字符串很庞大记得在对它使用正则表达式之前用官方方法对它study一下
study($string);
据说这样可以提高一点性能其实如果要性能还是建议用JavaJava也有正则表达式或者对性能有更高要求的话建议用C/C++标准的C和C++都不支持正则表达式但有一些函数库可以辅助C/C++程序员完成这一功能其中最著名的当数PhilipHazel的Perl-CompatibleRegularExpression库许多Linux发行版本都带有这个函数库使用方法看这里
http://www.chinaunix.net/jh/23/303346.html
在Windows上面VC.NET(VC7)框架里是有正则表达式了警告微软的老大们并没有实现Perl兼容例如在Perl中{,1}是{0,1}的简写但.NET并不支持具体看这里
http://msdn2.microsoft.com/en-us/library/xbyh1eyc.aspx
参考
2009年5月3日星期日
订阅:
博文评论 (Atom)
0 评论:
发表评论