Files
devops/perl/perlonelinecn-master/07正则表达式.md
2025-09-17 16:08:16 +08:00

7.4 KiB
Raw Blame History

正则表达式

112.匹配貌似邮件的正则表达式

 /^\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}.重复三次的到同样功能的表达式:

/^(\d{1,3}\.){3}\d{1,3}$/

113.测试数字是否在0-255的范围内

/^([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地址

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地址。

/.+@.+\..+/

这个正则确保字符串看起来像一个邮件地址。注意到这说的是"看起来像"。它不能保证确实是一个邮件地址。他的匹配过程是:首先匹配一些字符后跟个@符号,接着匹配任意字符然后到发现一个点,接着匹配更多个字符。如果这个匹配成功,那么这个字符串至少看起来就像个个邮件地址,他有@和.。 例如,admin@ijz.me可以匹配但是admin@ijzme不会匹配因为他匹配不到点.,这是必须的。 其实更可靠检测合法邮件地址的方法是是用Email::Valid 模块:

use Email::Valid;
print (Email::Valid->address('john@example.com') ? 'valid email' : 'invalid email');

116.检测字符串为十进制数。

检测字串是否是数字非常难。我基于正则并且在Perl Cookbook对其做了解释。

/^\d+$/

这个正则匹配一个或者更多的数字\d为了开始符^和结尾符$。但是它不能匹配诸如+3和-3这样的数字。让我们调整一下匹配他们

/^[+-]?\d+$/

此处[+-]?意思是在数字前匹配一个可选的正号或者负号。这个可以匹配+3或者-3但是还不能匹配-0.3。让我们加上它:

/^[+-]?\d+\.?\d*$/

我们在前一个正则的基础上加了.?\d*,这匹配了一个可选的.在0或者其他数字后面。现在这个正则可以匹配诸如-0.3或者0.3的数字了。 更好的方式是是使用Regexp::Common模块它提供了各种非常有用的正则表达式。比如匹配一个整数你可以用$RE{num}{int}。 那么怎么匹配一个正16进制数字呢见下式

/^0x[0-9a-f]+$/i

这可以匹配十六进制前缀0x紧跟着数字。模式结尾的/i标志确保匹配是不区分大小写的。例如0x57af匹配0X5Fa也匹配但是97匹配不了由于他是一个十进制数。

当然最后是用模块$RE{num}{hex},它会支持负数,小数和逗点的数字组。 那么八进制呢?见下:

/^0[0-7]+$/

8进制数前缀是0其后紧跟八进制数字0-7。例如013匹配但是09不会匹配因为9不是一个合法的八进制数。 更好的方式是使用$RE{num}{oct},好处同上。

最后2进制

/^[01]+$/

二进制只包含0和1.例如0101101匹配但是210101不能因为2不是合法的二进制数字。

更好的方式是使用$RE{num}{bin}。

117.检测一个单词在字符串总出现了两次。

/(word).*\1/

这个正则匹配了word紧跟着任意字符随后是同样的word。此处word捕捉了word 分组1并用\1引用了分组1的内容因此这个和写作/word.word/的模式一样。例如“silly things are silly”会匹配/(silly).\1/但是“silly things are boring”不会匹配因为后面这个字串中silly没有重复。

118.给字串中的所有数字加1.

$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头中用户客户端字串

/^User-Agent: (.+)$/

HTTP头以键值对的格式表示的。操作这些字串很简单你只要叫正则机保存值部分在$1组变量。 例如如果HTTP头包含

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.匹配可打印字符。

/[ -~]/

这个一个非常巧妙的表达式。为了理解他看下ascii的说明。你可以发现空格符起始于0x20符号是0x7e。所有的空格和之间的字符的都是可以打印字符。这个正则表达式恰好匹配了这些。[ -]定义了一个从空格到的字符范围。这一直是我最喜欢的正则表达式。 /[^ -~]/

这个匹配恰好和[ -~]相反。

121.匹配两个HTML签之间的文本

m|([^<]*)|

这个正则表达式匹配了所有... 签之间的内容。此处技巧是([^<]*),它匹配会匹配尽可能多的字符知道发现一个<字符,他会开始另一个标签。 另外你也可以写成:

m|(.*?)|

但是这个有点不一样了。例如如果HTML内容是 hello 则第一个正则不能匹配但是第二个正则表达会匹配到hello由于(.*?)匹配尽可能少的内容知道发现。这恰好是hello。 但是我们一般不建议用正则表达式去匹配和处理HTML。使用诸如HTML::TreeBuilder 模块去做这项工作,是更明智的选择。

122.替换所有的签为

$html =~ s|<(/)?b>|<$1strong>|g

此处我假设HTML内容保存在变量$html中。接着<(/)?b>匹配了起始和结束的签,捕捉可选的可选签在组$1接着用 或者 替换匹配的签这取决于匹配的是一个起始或者结束tag签。

123.提取正则表达式中所有匹配的部分。

my @matches = $text =~ /regex/g;

此处正则表达式在list上下文中使得他返回所有匹配。匹配的内容被放进@matches数组中。 例如,下面的正则表达式提取了一个字符串中所有的数字。

my $t = "10 hello 25 moo 31 foo";
my @nums = $text =~ /\d+/g;
@nums 现在包含了(10, 25, 30)。