Perl的正则表达式支持
- 使用简单模式
若模式匹配的对象是$_的内容,只需把模式写在一对斜线(/)中就可以了。
$_="yabde sdfe doo";
if(/sdfe/){
print "matched!\n"
}
在简单模式匹配中如何使用不匹配的模式(反模式)
# 输出不包含"/bin/bash"的行
......
if(/^((?!\/bin\/bash).)*$/){
......
}
......
# 命令行方式
getent passwd | perl -ne 'print if /^((?!\/bin\/bash).)*$/'
这里使用到的反模式是
# 不包含string的行
/^((?!string).)*$/
- Unicode属性匹配
if(/\p{Space}/){ #带有空白字符的属性
...
}
if(/\p{Digit}/){ #数字字符
...
}
if(/\p{Hex}\p{Hex}/){ #匹配2位十六进制数
...
}
if(/\P{Space}/){ #非空白字符
...
}
- 反向引用
$_="abba";
if(/(.)\1/){
...
}
消除反向引用的奇异
$_="aa11bb";
if(/(.)\g{1}11/){ #绝对分组编号
...
}
相对分组编号
$_="xaa11bb";
if(/(.)(.)\g{-1}11/){ #本尊的前一个引用
...
}
按老的ASCII字符集来解释
if(/\s/a){
...
}
- 通用断行符
\R会匹配:
\r\n
\n
-
正则表达式匹配
匹配方式” m// “,其中的” / “可以使用其他字符,如##,!!,^^,(),{},<>,[]等。
当使用/时,可以省略m。 -
模式匹配修饰符
修饰符 | 含义 |
---|---|
/a | 使用ASCII字符集 |
/u | 使用unicode字符集 |
/i | 大小写无关匹配 |
/s | . 无法匹配换行符。这适用于单行匹配。用于匹配字符串中的回车换行符。 |
/x | 模式字符串中可以有额外的空白符。还可以忽略#注释。 |
上述修饰符可以组合使用,且不用操心先后顺序。
注意:
\N表示非\n。
7. 锚位
绝对开头
m{\Ahttps?://}i
绝对末尾
m{\.png\z}
\Z允许后边出现换行符。
while(<STDIN>){
print if /\.png\Z/;
}
while(<STDIN>){
chomp;
print "$_\n" if /\.png\z/;
}
匹配含空白的行
/\A\s*\Z/
- 绑定操作符=~
默认匹配$_,通过=~来绑定匹配模式。
if($some_other =~ /\brub/){
...
}
- 模式中的内插
if(/\A($what)/){
...
}
10.捕获变量
在匹配操作结束后通过捕获变量取得捕获组的内容。
$1 $2 $3 …
$_="Hello there, neighbor";
if(/(\S+) (\S+), (\S+)/){
print "words were $1 $2 $3\n";
}
匹配变量存活到下次匹配成功为止。
失败的匹配不会改动上次成功匹配时捕获的内容,而成功的匹配会将它们的值重置。
- 自动捕获变量
字符串里实际匹配模式的部分会被自动存进$&变量里。
$&里保存的是整个匹配区段。
匹配区段之前的内容会存到“ $` ”里,而匹配区段之后的内容则会存到“ $' ”里。
另外一个理解方法是,“ $` ”保存了正则表达式引擎在找到匹配区段之前略过的部分,
而“ $' ”则保存了字符串中剩下的从未被匹配到的部分。如果将这三个字符串一次连接起来,
就一定会得到原字符串。
if("Hello there, neighbor" =~ /\s(\w+),/){
print "That was ($`)($&)($')";
}
回显
That was (Hello)( there,)( neighbor)
自动捕获变量比捕获变量效率低些。
也可以使用如下的方法等效替代
if("Hello there, neighbor" =~ /\s(\w+),/p){
print "That was (${^PREMATCH})(${^MATCH})(${^POSTMATCH}).\n";
}
- 正则表达式优先级
正则表达式特性 | 实例 |
---|---|
圆括号(分组或捕获) | (…), (?:…), (?<LABEL>…) |
量词 | a*, a+, a?, a{n,m} |
锚位和序列 | abc, ^, $, \A, \b, \z, \Z |
择一竖线 | A│B│C |
原子 | a, [abc], \d, \1, \g{2} |
一个测试程序
#!/bin/perl
while(<>){
chomp;
if(/YOUR_PATTERN/){
print "Matched: ($`<$&>$')\n";
}else{
print "No matched: ($_)\n";
}
}
又一个例子
while(<>){
chomp;
print "$&\n" if /\d+\.\d+\.\d+\.\d+/;
}
- 如何取出一行中所有的匹配?
echo "(21,0,0)(110,33,0)(117,1,2)" | perl -ne '@d = /\((\d+)/g; print join "\n", @d; print "\n"'
echo "(211,0,0)(110,33,0)(117,1,2)" | perl -ne 'my @re=/\((\d+)/g;foreach (@re){print "$_\n"}'
取出一行中的所有IPv4地址
#!/usr/bin/perl
while(<>){
chomp;
my @ip=/\d+\.\d+\.\d+\.\d+/g;
foreach(@ip){
print "$_\n";
}
}
对比shell script
grep -E -o "((1[0-9][0-9]\.)|(2[0-4][0-9]\.)|(25[0-5]\.)|([1-9][0-9]\.)|([0-9]\.)){3}((1[0-9][0-9])|(2[0-4][0-9])|(25[0-5])|([1-9][0-9])|([0-9]))" case1.txt
转换成数组
my @words=($line =~ /([a-z]+)/ig); #将模式绑定到$line而非$_,模式将作用于$line。
转换为哈希
my %last_name=($data =~ /(\w+)\s+(\w+)/g);
- 如何分割获取字符串的各个列?
$info="Caine:Michael:Actor:14,LeafyDrive";
@personal=split(/:/,$info);
my @fields=split /\t/, $string;
my @fields=split /\s+/,$some_input;
有时对于简单的分列需求也可以
my($name, $age, $addr, $work)=split /:/;
对于空字段可以如下处理
my(undef, $card, undef, undef, $work)=split /:/;
默认split会以空白符分割$_中的字符。
my @fields=split;
对于CSV文件,最好使用CPAN上的模块Text::CSV。
yum install -y perl-CPAN
join与split相反:
my $x=join ":",4,5,6,7; # $x 为“4:5:6:7”
- 用s///进行替换
s/with (\w+)/against $1's team/;
print "$_\n";
s///返回布尔值,替换成功为真,否则为假。
/g可以替换所有可能。
去除开头和结尾的空格
s/^\s+|\s+$//g
“ / ”可以使用其他字符作为分隔符,只要重复3次。
绑定操作符的例子
$file_name =~ s#^.*##s;
无损替换
my $copy=$original =~ s/\d+ ribs?/10 ribs/r;
加上/r之后,就会保留原来字符串变量中的值不变,而把替换结果作为替换操作的返回值返回。
大小写转换
s/(fred|barney)/\U$1/gi; #不使用绑定操作符绑定到其他变量,默认就绑定到$_。
\U会将其后的所有字符转换成大写的。同理,\L会将其后的所有字符转换成小写的。可以使用\E终止大小写转换的作用。
s/(\w+) with (\w+)/\U$2\E with $1/i;
\l和\u只会影响紧跟其后的一个字符。
- 列表上下文中的m//
$_="Hello there, neighbor";
my($first,$second,$third)=/(\S+) (\S+), (\S+)/;
print "$second is my $third\n";
或者
echo "Hello there, neighbor" | perl -ne 'my($first,$second,$third)=/(\S+) (\S+), (\S+)/;print "$second is my $third\n"'
- 备份文件
<> 结合对“ $^I ”变量赋值。
定义备份文件扩展名。
$^I = ".bak";
- 命令行形态的perl
$ perl -p -i.bak -w -e 's/Randall/Randal/g' fred*.dat
等效于如下代码:
#!/usr/bin/perl -w
$^I=".bak";
while(<>){
s/Randall/Randal/g;
print;
}
常用命令行参数
参数 | 作用 |
---|---|
-p | 生成程序片段 while(<>){ print; } |
-n | 生成程序片段 while(<>){ } |
-i | 在程序运行之前把 $^I 设置为备份文件后缀名 |
-w | 开启告警功能 |
-e | 后边是可执行的perl代码。代码会处于print前边。代码片段末尾可以省略分号。如果有多个-e选项,就会有多段程序代码。此时只有最后一段末尾的分号可以省略。 |
来个例子
$ perl -e 'print "$ENV{PATH}\n"'