Perl学习笔记-2(正则表达式)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Perl学习笔记-2(正则表达式)相关的知识,希望对你有一定的参考价值。


Perl的正则表达式支持

  1. 使用简单模式
    若模式匹配的对象是$_的内容,只需把模式写在一对斜线(/)中就可以了。
$_="yabde sdfe doo";
if(/sdfe/)
print "matched!\\n"

在简单模式匹配中如何使用不匹配的模式(反模式)

# 输出不包含"/bin/bash"的行
......
if(/^((?!\\/bin\\/bash).)*$/)
......

......

# 命令行方式
getent passwd | perl -ne print if /^((?!\\/bin\\/bash).)*$/

这里使用到的反模式是

# 不包含string的行
/^((?!string).)*$/
  1. Unicode属性匹配
if(/\\pSpace/) #带有空白字符的属性
...

if(/\\pDigit/) #数字字符
...

if(/\\pHex\\pHex/) #匹配2位十六进制数
...

if(/\\PSpace/) #非空白字符
...
  1. 反向引用
$_="abba";
if(/(.)\\1/)
...

消除反向引用的奇异

$_="aa11bb";
if(/(.)\\g111/) #绝对分组编号
...

相对分组编号
$_="xaa11bb";
if(/(.)(.)\\g-111/) #本尊的前一个引用
...

按老的ASCII字符集来解释

if(/\\s/a)
...
  1. 通用断行符
\\R会匹配:
\\r\\n
\\n
  1. 正则表达式匹配
    匹配方式” m// “,其中的” / “可以使用其他字符,如##,!!,^^,(),,<>,[]等。
    当使用/时,可以省略m。
  2. 模式匹配修饰符

修饰符

含义

/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/
  1. 绑定操作符=~
    默认匹配$_,通过=~来绑定匹配模式。
if($some_other =~ /\\brub/)
...
  1. 模式中的内插
if(/\\A($what)/)
...

10.捕获变量
在匹配操作结束后通过捕获变量取得捕获组的内容。
$1 $2 $3 …

$_="Hello there, neighbor";
if(/(\\S+) (\\S+), (\\S+)/)
print "words were $1 $2 $3\\n";
匹配变量存活到下次匹配成功为止。
失败的匹配不会改动上次成功匹配时捕获的内容,而成功的匹配会将它们的值重置。
  1. 自动捕获变量

字符串里实际匹配模式的部分会被自动存进$&变量里。
$&里保存的是整个匹配区段。

匹配区段之前的内容会存到“ $` ”里,而匹配区段之后的内容则会存到“ $ ”里。
另外一个理解方法是,“ $` ”保存了正则表达式引擎在找到匹配区段之前略过的部分,
而“ $ ”则保存了字符串中剩下的从未被匹配到的部分。如果将这三个字符串一次连接起来,
就一定会得到原字符串。
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";
  1. 正则表达式优先级

正则表达式特性

实例

圆括号(分组或捕获)

(…), (?:…), (?<LABEL>…)

量词

a*, a+, a?, an,m

锚位和序列

abc, ^, $, \\A, \\b, \\z, \\Z

择一竖线

A│B│C

原子

a, [abc], \\d, \\1, \\g2

一个测试程序

#!/bin/perl
while(<>)
chomp;
if(/YOUR_PATTERN/)
print "Matched: ($`<$&>$)\\n";
else
print "No matched: ($_)\\n";

又一个例子

while(<>)
chomp;
print "$&\\n" if /\\d+\\.\\d+\\.\\d+\\.\\d+/;
  1. 如何取出一行中所有的匹配?
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]))"

转换成数组

my @words=($line =~ /([a-z]+)/ig); #将模式绑定到$line而非$_,模式将作用于$line。

转换为哈希

my %last_name=($data =~ /(\\w+)\\s+(\\w+)/g);
  1. 如何分割获取字符串的各个列?
$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

join与split相反:

my $x=join ":",4,5,6,7; # $x 为“4:5:6:7”
  1. 用s///进行替换
s/with (\\w+)/against $1s 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只会影响紧跟其后的一个字符。

  1. 列表上下文中的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"
  1. 备份文件
    <> 结合对“ $^I ”变量赋值。
定义备份文件扩展名。
$^I = ".bak";
  1. 命令行形态的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 "$ENVPATH\\n"


以上是关于Perl学习笔记-2(正则表达式)的主要内容,如果未能解决你的问题,请参考以下文章

PHP整理笔记八正则表达式

perl学习模式匹配与正则表达式

perl学习正则表达式

Perl正则表达式:开篇

perl学习正则表达式处理文本

正则表达式的基本用法