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

147 lines
7.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 正则表达式
## 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)。