perl one-liners explained,是继《Famous Awk One-Liners Explained》和《Famous Sed One-Liners Explained》,后Peteris Krumin推出的又一个系列文章,并已经出书了。本blog会陆续对其进行翻译成中文,以便大家学习。本篇是第六部分——正则表达式
原文地址:http://www.catonmat.net/download/perl1line.txt
原书blog地址:http://www.catonmat.net/blog/perl-book/
本翻译项目地址:https://github.com/bollwarm/perlonelinecn
正则表达式
112.匹配貌似邮件的正则表达式
1 2 |
/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/ |
这个正则表达式不能保证匹配都是合法的ip地址,匹配成功只不过貌似ip地址的字串。比如,它可以匹配一个合法的ip地址81.198.240.140,同时也能匹配一个非法ip地址比如923.844.1.999。 下面解释他是如何工作的。正则开始的^符号是一个锚字符,用来匹配一个字串的开始。接着\d{1,3}匹配一个,两个或者三个连续数字。“.”匹配一个点。最后的$也是一个锚字符匹配字段的结尾。使用^和$锚字符非常有必要,否则的话诸如“foo213.3.1.2bar”一样的字串也会被匹配上。 这个正则可以简单的把开始部分\d{1,3}.重复三次的到同样功能的表达式:
1 2 |
/^(\d{1,3}\.){3}\d{1,3}$/ |
113.测试数字是否在0-255的范围内
1 2 |
/^([0-9]|[0-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$/ |
让我来看这个正则是如何工作的。此范围内的数可以为一个,两个或者三个数字。如果是一个数字,我们可以让它为任何[0-9]。如果是两个数字,我们也允许它为任何[0-9][0-9]的组合。然而如果它是三个数字的,则他必须为100多或者200多的数。如果为100多的,可以用1[0-9][0-9]匹配它。如果是200多的数字,如果是小于250的,可以用2[0-4][0-9]匹配。或者250-255的,用25[0-5]匹配。
114.匹配IP地址
1 2 3 4 5 |
my $ip_part = qr|([0-9]|[0-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])|; if ($ip =~ /^($ip_part\.){3}$ip_part$/) { say "valid ip"; } |
本正则组合了前面的两个。它用my $ip_part=qr/…/操作把正则表达式组合到一起,并且存到$ip_part变量中。接着用这个变量去匹配IP地址的四个部分。
115.检查字符串是否貌似email地址。
1 2 |
/.+@.+\..+/ |
这个正则确保字符串看起来像一个邮件地址。注意到这说的是看“起来像”。它不能保证确实是一个邮件地址。他的匹配过程是:首先匹配一些字符后跟个@符号,接着匹配任意字符然后到发现一个点,接着匹配更多个字符。如果这个匹配成功,那么这个字符串至少看起来就像个个邮件地址,他有@和.。 例如,[email protected]可以匹配,但是admin@ijzme不会匹配,因为他匹配不到点.,这是必须的。 其实更可靠检测合法邮件地址的方法是是用Email::Valid 模块:
1 2 |
use Email::Valid; |
116.检测字符串为十进制数。
检测字串是否是数字非常难。我基于正则并且在Perl Cookbook对其做了解释。
1 2 |
/^\d+$/ |
这个正则匹配一个或者更多的数字\d为了开始符^和结尾符$。但是它不能匹配诸如+3和-3这样的数字。让我们调整一下,匹配他们:
1 2 |
/^[+-]?\d+$/ |
此处[+-]?意思是在数字前匹配一个可选的正号或者负号。这个可以匹配+3或者-3,但是还不能匹配-0.3。让我们加上它:
1 2 |
/^[+-]?\d+\.?\d*$/ |
我们在前一个正则的基础上加了.?\d*,这匹配了一个可选的.在0或者其他数字后面。现在这个正则可以匹配诸如-0.3或者0.3的数字了。 更好的方式是是使用Regexp::Common模块,它提供了各种非常有用的正则表达式。比如,匹配一个整数你可以用$RE{num}{int}。 那么怎么匹配一个正16进制数字呢?见下式:
1 2 |
/^0x[0-9a-f]+$/i |
这可以匹配十六进制前缀0x,紧跟着数字。模式结尾的/i标志确保匹配是不区分大小写的。例如0x57af匹配,0X5Fa也匹配,但是97匹配不了,由于他是一个十进制数。
当然最后是用模块$RE{num}{hex},它会支持负数,小数和逗点的数字组。 那么八进制呢?见下:
1 2 |
/^0[0-7]+$/ |
8进制数前缀是0,其后紧跟八进制数字0-7。例如,013匹配,但是09不会匹配,因为9不是一个合法的八进制数。 更好的方式是使用$RE{num}{oct},好处同上。
最后2进制:
1 2 |
/^[01]+$/ |
二进制只包含0和1.例如,0101101匹配,但是210101不能,因为2不是合法的二进制数字。
更好的方式是使用$RE{num}{bin}。
117.检测一个单词在字符串总出现了两次。
1 2 |
/(word).*\1/ |
这个正则匹配了word紧跟着任意字符,随后是同样的word。此处(word)捕捉了word 分组1,并用\1引用了分组1的内容,因此这个和写作/(word).word/的模式一样。例如,“silly things are silly”会匹配/(silly).\1/,但是“silly things are boring”不会匹配,因为后面这个字串中silly没有重复。
118.给字串中的所有数字加1.
1 2 |
$str =~ s/(\d+)/$1+1/ge |
此处我们使用替换操作符s///。他匹配所有的数字(\d+),把他们捕捉到组1,接着把他们的值替换其值加1后的值。g标志确保它会知道字串中的所有的数字,e标志使得$1+1作为一个Perl表达式执行。 例如,“this 1234 is awesome 444”会被替换为“this 1235 is awesome 445”。
119. 提取HTTP头中用户客户端字串
1 2 |
/^User-Agent: (.+)$/ |
HTTP头以键值对的格式表示的。操作这些字串很简单,你只要叫正则机保存值部分在$1组变量。 例如,如果HTTP头包含,
1 2 3 4 5 6 7 8 9 |
Host: localhost:8000 Connection: keep-alive User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_0_0; en-US) Accept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5 Accept-Encoding: gzip,deflate,sdch Accept-Language: en-US,en;q=0.8 Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3 . |
那么正则表示式将会提取Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_0_0; en-US)字串
120.匹配可打印字符。
1 2 |
/[ -~]/ |
这个一个非常巧妙的表达式。为了理解他,看下ascii的说明。你可以发现空格符起始于0x20,符号~是0x7e。所有的空格和~之间的字符的都是可以打印字符。这个正则表达式恰好匹配了这些。[ -~]定义了一个从空格到的~字符范围。这一直是我最喜欢的正则表达式。 /[^ -~]/
这个匹配恰好和[ -~]相反。
121.匹配两个HTML签之间的文本
1 |
m|([^<]*)| |
这个正则表达式匹配了所有… 签之间的内容。此处技巧是([^<]*),它匹配会匹配尽可能多的字符知道发现一个<字符,他会开始另一个标签。 另外你也可以写成:
1 2 |
m|(.*?)| |
但是这个有点不一样了。例如,如果HTML内容是 hello 则第一个正则不能匹配,但是第二个正则表达会匹配到hello,由于(.*?)匹配尽可能少的内容知道发现。这恰好是hello。 但是我们一般不建议用正则表达式去匹配和处理HTML。使用诸如HTML::TreeBuilder 模块去做这项工作,是更明智的选择。
122.替换所有的签为
1 |
$html =~ s|<(/)?b>|<$1strong>|g |
此处我假设HTML内容保存在变量$html中。接着<(/)?b>匹配了起始和结束的签,捕捉可选的可选签在组$1,接着用 或者 替换匹配的签,这取决于匹配的是一个起始或者结束tag签。
123.提取正则表达式中所有匹配的部分。
1 2 |
my @matches = $text =~ /regex/g; |
此处正则表达式在list上下文中,使得他返回所有匹配。匹配的内容被放进@matches数组中。 例如,下面的正则表达式提取了一个字符串中所有的数字。
1 2 3 4 |
my $t = "10 hello 25 moo 31 foo"; my @nums = $text =~ /\d+/g; @nums 现在包含了(10, 25, 30)。 |