Perl-正则表达式

正则表达式:regular expression (regex)‘,用以描述具有某种特征模式的字符串

1. 序列

perl的正则表达式要么匹配某个字符串,要么不匹配,没有介于中间的部分匹配
perl会寻找从左起尽可能长的符合条件的匹配字符串

最简单的匹配模式是序列,要找什么字符直接写到匹配模式中

$_ = "yabba dabba doo";
if(/abba/){
	print "It matched!\n";
}

if语句的条件表达式中,2个斜线就是匹配操作符,默认用它匹配$_中的字符串,斜线之间的部分就是要匹配的模式

匹配过程是从最左侧开始尝试匹配的,找到之后不会继续看后面的dabba是否也匹配,这与全局匹配不一样

在perl模式中,空白字符值得关注,任何在模式中写明要匹配的空白字符,意思就是要寻找匹配$_中完全相同的空白字符

$_ = "yabba dabba doo";
if(/ab ba/){ # 不能匹配
	print "It matched!\n";
}

$_ = "yabba dabba doo";
if(/ba da/){ # 能匹配
	print "It matched!\n";
}

写在匹配操作符中的模式文本相当于写在双引号内,比如\t和\n这样的特殊序列表示的就是制表符和换行符

制表符的N中表示方式

/coke\tsprite/ # \t表示制表符
/coke\N{CHARACTER TABULATION}sprite/ # \N{charname}
/coke\011sprite/ # 字符的八进制码
/coke\x09sprite/ # 字符的十六进制码
/coke\x{9}sprite/ # 字符的十六进制码
/coke${tab}sprite/ # 标量变量

perl在运行时先完成变量内插,取得表示模式的字符串后,再编译这个正则表达式,编译时如果发现这个字符串非法,会收到错误信息

$pattern = "(";
if(/$pattern/){
	print "It matched!\n"; # 编译错误,因为括号在perl中有特殊意义
}

用1个空的序列去匹配,配啥都唔那个匹配上

$_ = "yabba dabba doo";
if(//){
	print "It matched!\n";
}

根据“从最左侧起最长匹配”的原则,在字符串开始的位置总是可以匹配一个没有长度的序列

2. 动手实践不同模式

模式字符串可以用变量内插,改成从命令行接受参数,作为要要测试的模式是不是会更好?

while (<STDIN>){
	chomp;
	if(/$ARGV[0]/){ # 直接使用参数会有安全隐患
		print "\tMatches\n";
	}else{
		print "\tDoesn't match\n";
	}
}

因为输入的参数可以是任何东西,而perl拿到之后直接当正则表达式进行编译运算,所以从命令行接受参数会有安全隐患

% perl try_a_pattern "fred"
This will match fred
	Matches
But not Barney
	Doesn't match	

现在可以不改程序代码就直接测试不同模式了

% perl try_a_pattern "barney"
This will match fred (not)
	Doesn't match
But it will match barney
	Matches

3. 通配符

点号. 能匹配除换行符外的任意单个字符
perl认为一般意义上我们要匹配的是换行符前的文本,那才是输入的内容,而换行符不过是行与行间的分隔,是格式的一部分

$_ = "yabba dabba doo!";
if(/doo./){ # 能匹配
	print "It matched!\n";
}

$_ = "yabba dabba doo\n";
if(/doo./){ # 不能匹配
	print "It matched!\n";
}

如果像匹配实际的点号字符,需要先用反斜线转义

$_ = "yabba dabba doo.";
if (/doo\./){ # 能匹配
	print "It matched!\n";
}

perl5.12增加了另一个“能匹配除换行符外任意单个字符”的写法 \N

4. 量词

可以用量词来指定匹配项的重复次数,量词也是元字符,量词把它之前的字符作为要匹配的目标,然后定义它该重复匹配的次数

匹配次数元字符一般化写法
可有可无?{0,1}
0或多次*{0,}
1次以上+{1,}
至少多少次{3,}
指定重复次数范围{3,5}
准确的重复次数{3}

5. 模式分组

圆括号将模式字符串进行分组,圆括号也是元字符
量词只作用于它前面的那个字符,模式/fred+/匹配的是freddddddddd这样的字符串,因为量词+之前的是字母d。如果要匹配整个fred的重复次数,就需要用括号把fred括起来,写成/(fred)+/,这个时候匹配的是fredfredfred这样的字符串

圆括号还能帮助重复利用匹配上的字符串,可以使用反向引用(back reference),引用圆括号匹配到的字符
由于能取得匹配结果,这种括号围起来的分组叫做捕获分组(capture group)
反向引用:在反斜线后面接上数字,每个数字代表对应的捕获分组,按括号出现的先后次序而定

$_ = "abba";
if(/(.)\1/){ # 匹配连续出现的2个同样的字符,能匹配'bb'
	print "It matched same character next to itself!\n";
}

$_ = "yabba dabba doo";
if(/y(....) d\1/){ # 反向引用不需要紧贴在对应捕获分组括号的右边
	print "It matched the same after y and d!\n";
}

$_ = "yabba dabba doo";
if(/y(.)(.)\2\1/){ # 可以用多个括号形成不同分组,每个分组对应1个编号,1个编号对应1个反向引用,这个用来匹配像abba这样的回文
	print "It matched after the y!\n";
}

$_ = "yabba dabba doo";
if (/y((.)(.)\3\2) d\1/){ # 如何知道某个分组对应的数字编号?不用管嵌套的情况,从左起数左括号出现的次序即可
	print "It matched!\n";
}

perl5.10引入了1个新的标记反向引用的写法 \g{N},其中g表示分组,N就是原来的数字编号,而\g{N}也可以简写为\gN

perl会据需创建反向引用,但只保留\1到\9的缓存

$_ = "aa11bb";
if(/(.)\111/){
	print "It matched!\n"; # 反向引用是\1还是\11或者是\111呢?计算机需要推测你的推测
}

编号数字可以使用负数,和python差不多

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值