Perl语言入门笔记:第十二天
时间:2010-09-03 来源:linscora
以正则表达式进行匹配:
正则表达式如何与Perl接轨呢? 以m//进行匹配
前面我们用/fred/要编写模式,事实上,它是m//(模式匹配)操作符的简写。也可以用m() m<> m{} m[]这样的模式。 用/^http:\/\//匹配http:// 和m%^http://%是一样的 可选修饰符:
一些可有可无的修饰符有时候称为开关。它们可以成组附加在某个正则表达式结尾的定界符的右边,并改变正则表达式的默认行为。 用/i来进行大小写无关的匹配:
#!/usr/bin/perl -w |
用/x加入空白:
/x可以在模式里面随意加上空白,使//里面的内空更容易阅读和理解。
/-?\d+\.?\d*/ #挤在一起,很难看清是什么意思。
/ -? \d+ \.? \d* /x #加入空白后,稍微清楚些。
加入/x之后模式里面可以任意插入空白,所以原始的空白与制表符就推失去意义了,它们会被忽悠。如果还要匹配空白与制表符的话,就得在前面补上一个反斜线字符(也可以采用其他方式),不过\s(\s*)(\s+)还是比较常见的匹配空白的写法。
Perl里,注释也算一种空白。所以我们可以借机在模式里写上注释以指明其用途。
/
-? #零个或一个减号
\d+ #一个或多个数字
\.? #零个或一个小数点
\d* #零个或多个数字
/x #字符串结尾
\# 表示真正的#号
组合选项修饰符:
如果在一个模式中使用多个修饰符,可将它们连在一起使用。它们之间的先后
if (/barney.*fred/is) { #同时使用/i 和 /s |
注意,些处花括号为定界符,这让程序员专用的编辑器可以方便地(在正则表达式的两头间)跳转。
锚位:
默认情况下,模式匹配的过程开始于待匹配字符串的开头,如果不相符就一直往字符串后面浮动,看其他位置能否匹配。但是加入一些锚位,可以让模式直接匹配字符串的某处。
脱字符(^)是一个锚位,用来标示字符串的开头,而美元符号($)也是一个锚位,用来标示字符串的结尾。
/^fred/只匹配位于字符串最前端的fred,如果manfred mann这个字符串,则不能匹配。而/rocks$/也只匹配位于字符串最后面的rock,如果是knute rockne,也同样失败。值得注意的是:/^fred$/会匹配fred与fred\n这两个字符串。
两个锚位会一起使用,以确保模式可以匹配整个字符串。/^\s*$/这个模式可以匹配空白行。
单词锚位:
锚位并不限开字符串的首尾。比如\b是单词边界锚位,它匹配任何单词的首尾。
如:/\bFred\b/可匹配fred但无法匹配fredrick、alfred或manfredmann。这在文字处理器的搜索命令里,通常称为整词搜索模式。
不过,这里所说的单词并不是一般的英文单词,而是由一组\w字符构成的字符集,也就是由普通英文字母、数字与下划线组成的单词。\b锚位匹配是一组\w字符的开头或结尾。
用\b匹配单词边界:
/\bhunt/匹配 hunt hunting hunter 排除了shunt
/stone\b/匹配 standstone flintstone
用\B匹配非单词边界锚位:
/\bsearch\B/ 匹配searchs searching searched 但不匹配search或researching
绑定操作符:
默认情况下模式匹配的对象是$_,绑定操作符=~则能让Perl拿右边的模式来匹配左边的字符串,而非匹配$_。
my $some_other = "I dream of betty rubble."; |
在上面例子里,$likes_perl会被赋予一个布尔值,这个结果取决于用户键入的内容。判断之后丢弃了用户的输入。
这行代码大致上的功能是读取输入行,匹配字符与模式,然后舍弃输入行的内容。没有进一步使用$_,也没有改变它。
模式串中的内插:
正则表达式可以进行双引号形式的内插。这让我们可以很快写出类似grep的程序:
#!/usr/bin/perl -w |
请记住,除非while循环的条件表达式中只有整行输入操作符(<STDIN>),否则输入行不会自动存入$_。
$what不一定来自字符串直接量,我们可以从@ARGV里的命令行参数来取得:
my $what = shift @ARGV;
如果第一个命令行参数是fred|barney,刚模式会变成/^(fred|barney)/,也就是在每一行开头寻找fred或barney。寻找larry时多余的圆括号现在变得很重要,如果没它们,模式就会在字符串开头匹配fred或者在字符串任何地方匹配 barney。
如果$what的值为fred(barney),则模式就会变成/^(fred(barney)/,你也不知道这样是不会正确工作的,它会以invalid regular expression错误平中断你的程序。有一些高级技巧,可捕获这类错误(或者从一开始就解除元字符的魔法),让它不再中断你的程序。不过目前只需要记住,一旦赋予使用正则表达式的权力,他们就该负起正确使用的责任。
捕获变量:
每当我们在模式里使用圆括号的时候,都只是用来表示不同的模式组。但圆括号同时也启动了正则表达式处理引擎的捕获功能。捕获功能指的是,把(圆括号中模式匹配的)部分字符串暂时记下来的能力。如果有一对以上的圆括号,就会有一次以上的捕获。每个被捕获的对象是原本的字符串,而不是模式。
$_ = "Hello there, neighbor"; |
输出结果为: Hello there neighbor
注意这里there没有逗号。因为模式里的逗号放在圆捂外面,所以第二次捕获中不会有逗号。
使用这个技巧,我们可以精确筛选捕获的(和跳过的)数据。
有时可能产生空匹配变量,因为那部分的模式允许为空,也就是说要考虑捕获变量为空的情况。
#!/usr/bin/perl -w |
这些捕获变量通常能存活到下次成功的模式匹配为止。也就是说,失败的匹配不会改动上次成功匹配时捕获的内容,而成功的匹配会将它们重置。换句话说。捕获变量只应该在匹配成功时使用;否则就会得到之前一次模式匹配的捕获内容。
#!/usr/bin/perl -w |
目前所见的圆括号都会捕捉部分的匹配串到捕获变量中,但有时候却需要关闭这个功能,而仅仅只是用它来进行分组。
#!/usr/bin/perl -w |
Perl只是按左圆括号的序号来决定捕获变量名,这导致我们真正想捕获的内容只能进入$2。
还好Perl的正则表达式允许使用括号但不作捕捉。我们把这叫做不捕捉括号,书写时候有些差别。需要在左括号的后面加上问号和冒号(?:),以告知Perl这一对括号完全是为了分组而存在的。
?在正则表达式中有四种用法:原文问号(需要转义) 有无量词 非贪婪修饰符 不捕捉前缀 这四种。
下面我们用?:来跳过bronto,这样就可以用$1来捕获我们要的内容了。
if (/(?:bronto)?saurus (steak|burger)/) { |
命名捕捉:
虽然可以用括号的捕捉能力并且在$1、$2这样的变量中存取捕获的串。但是即使对于较为简单的模式来说,管理这样的数字变量比是比较困难的。
#!/usr/bin/perl -w |
use 5.010; |
这个say输的结果将是 I saw Fred and or,这也不是我们要的结果。
在Perl5.10引入了正则表达式命名捕捉的概念。现在捕捉的结果会进入一个特殊的哈希%+,其中的键就是在捕捉时候使用的特殊标签,其中的值则是被捕获的串。为捕获串加标签的方法是使用(?<LABEL>PATTERN)这样的写法,而LABEL可以自行命名。
#!/usr/bin/perl -w |
#!/usr/bin/perl -w |
Perl也允许用Python的语法(?P<LABEL>...)完成同样的功能。
自动匹配变量:
有三个不请自来的捕获变量,不必使用捕捉圆括号就能引入。这看来真是不错,但是这些变量的名称很奇怪。它们是: $& $` $'
if ("Hello there, neighbor" =~ /\s(\w+),/) { |
if ("Hello there, neighbor" =~ /\s(\w+),/) { |
通用量词:
模式中的量词代表前置条目的重复次数。到目前为止,我已经经见过三个量词:* + 和?。如果这三个量词都不符合需要。如果这三个量词都不符合需要,还可以在花括号({})里指定重复次数的范围。
/a{a,15}/ 可匹配重复出现5到15次的字母a。
/(fred){3,}/ 这个模式第二个数字没有但保留逗号,表次没有上限。
/\w{8}/ 表示8个字符的单词。
* 和 {0,} 一样
? 和 {0,1} 一样
优先级:
正则表达式优先级
正则表达式特性 例子
圆括号(分组或者捕获) (...), (?:...), (?<LABEL>...)
量词 a* a+ a? a{n,m}
锚位和序列 abc ^a a$
择一 a|b|c
元素 a [abc] \d \1
优先级实例:
/^fred|barney$/ 如果是这样的话,表示要不匹配字符串开头的fred,要不匹配字符结尾的barney
/^(fred|barnet)$/ 匹配只包含fred或是只包含barney的每一行。
/(wilma|pebbles?)/ 这个问号量词会紧接着前面的字符。所以它可以匹配到willma pebbles pebble
/^(\w+)\s+(\w+)$/ 匹配开始是一个单词、再来是一些空白、然后又是一个单词的行
模式测试程序: |