4.2 perl--用正则表达式进行匹配

之前我们看到,正则表示的写法的时候用的是//,比如说/fred/,实际上这是m//的简写,就像前面提到的数组qw//一样。同样的,m也可以任何成对或不成对的定界符,比如说m(fred).

我们可以选择模式中不会出现的字符来作为定界符,比如/http:\/\//,可以写为m%http://%。

常见的修饰符

/i  实现大小写无关的匹配
/s  匹配任意字符  因为.不能匹配换行符,而加上这个后,点号就能匹配任意的字符了
/x  容许在模式里随意地加入空字符
/a  选择ASCII码作为解释方式
/p  只会针对特定的正则表达式开启类似自动捕获变量
/g  全局替换

写法:

if (/yes/i)

注意:

#是注释符号,如果需要用的话,可以加上\,或者[#]。 这些修饰符可以放在一起,放在模式末尾,不必在意先后顺序。

Perl从5.14开始,有三种字符解释方式,ASCII,Unicode,locale。下面的修饰符分别告诉采取何种方式解释字符。

use5.014

/\w+/a    #仅仅表示A-Z,a-z,0-9
/\w+/u    #任何Unicode当中定义为单词的字符
/\w+/l    #类似ASCII的版本,但单词字符的定义取决于本地化定义
单个/a修饰符表示按照ASCII方式解释简写意义,如果使用两个/a,则进一步表示仅仅采用ASCII当时的大小写映射处理
/k/aai  #只匹配ASCII字符K或k,但不匹配开尔文符号

锚位

通过给定锚位,我们可以让模式仅在指定位置匹配

\A锚位匹配字符串的绝对开头
\z锚位字符串的绝对末尾
\Z锚位字符串绝对末尾,但容许出现换行符
\b是单词的边界锚位,它能匹配任何的那次的首位
\B 非单词边界锚位,它能匹配所有\b不能匹配的位置。
^  表示行首, $表示末尾,加上m后可以锚定多行的位置, 比如/^fred/m  /fred$/m  分别表示锚位与多行的行首和行尾
=~绑定操作符
默认情况下模式匹配的操作对象是$_,而绑定操作符则是告诉perl,拿右边的模式来匹配左边的字符串,而不是匹配$_

例如:

if ($some_other=~/\brub/){

金典的例子:

#! /usr/bin/perl -w
my $what="larry";
while(<>){
 if(/\A($what)/){
   print "We saw $waht in the beginning of $_";
    }
  }

这个例子中我比较喜欢$_,这个代表了输入行,自动被存入的。同时还有变量的内插,当然,如果加上=^就更牛逼了

捕获变量

变量$4的意思是模式中第4对括号所匹配的字符串内容,这个内容和模式运行期间反向引用\4所表示的内容是一样的。但他们并非同一个事物的两种名称:\4反向引用是模式匹配期间得到的结果,而$4则是匹配结束后所捕获的内容的索引。

if (/\s(a-zA-Z)+,/){  #捕获的是空白符和逗号之间的单词
    print $1;}         #$1为捕获的第一个变量

这些捕获的变量通常存活在下次匹配成功为止。如果需要在数行之外使用捕获变量,通常最好的做法就是将它复制到某个普通变量里。

if (/\s(a-zA-Z)+,/){  
    my $wilma= $1;

不捕获变量

有的时候,圆括号的加入仅仅是为了分组,所以要关闭它的捕获功能,只需要在左括号的后面加上?:来告诉perl这一对圆括号完全是为了分组而存在的,把变量名留出来

例如:

if (/(?:bronoto)?saurus(stedk|burger)/){    #这个里面$1为(stedk|burger)

命名捕获

use 5.010
my $names='Fred or Barney';
if ($names=^m/(?\w+)(?:and|or)(?\w+)/){
  say "T sam $+{name1} and $+{name2}";
   }

看明白了吗,通过(?PATTERN),其中LABERL可以自行命名,再通过$+{LABEL}来捕获它 在使用捕获标签后,反向引用的用法也随之改变,之前我们用\1或者\g{1}这样的写法,现在我们可以使用 \g{label}的写法

自动捕获变量

$& 字符串实际匹配模式部分会被自动存在
$`  匹配区段之前的的内容存在
$'  匹配区段之后的内容存在
但是呢,一旦用了这些自动捕获变量,其他正则表达式的运行速度就会变慢。
我们可以将这个的命名改一下,一下的是在5.10或以上的版本中使用
$&  ${^MATCH}来表示
$`  ${^PREMATCH}
$'  ${^POSTMATCH}

例如:

use 5.010;
if ("Hello,there,neighbor"=^/\s(\w+),/p){
  print "That actually matched '${^MATCH}'.\n"
   }

之前看到的三个量词:* + ?

如果这三个量词都不符合要求,我们还可以使用花括号{}形式指定具体的重复次数范围。

例如 /a{5,15}/其为5到15次的a

优先级
圆括号(分组或捕获)   (…)(?:…)(?…)
量词                    a*,a+,a?,a{n,m}
锚位和序列               abc,^,$,\A,\b,\z,\Z
折一竖线                 a|b|c
原子                     a,[abc],\d,\1,\g{2}

有的时候加上括号对弄清优先级有好处,但是圆括号的使用同时也会有捕获功能哦

例1:检测,是否能匹配到match

#! /usr/bin/perl
while (<>){
 chomp;
 if(/(match)/){
   print "Matched: |$`<$&>$'|\n";
     }else{
    print "No match:|$_|\n";
    }
   }

例2:检测以字母a结尾的单词,

#! /usr/bin/perl
use warnings;
use strict;
while (<>){
   chomp;
   if (/a\z/){
       print;
      }
      }

例3:以上面的为例子,将其存储在$1里

#! /usr/bin/perl
use warnings;
use strict;
while(<>){
   chomp;
   if (/([\d\D]+a\z)/){
   print "\$1 contains $1\n";
    }
    }

例4:接着上题,使用命名捕获

#! /usr/bin/perl
use warnings;
use strict;
while (<>){
    chomp;
  if (/(?[\d\D]*a\z)/){
    print "'word' contains $+{name}\n";
    }
    }

例5:定位以a结尾,但是再将之后的5个字符捕获至一个独立的内存变量

#! /usr/bin/perl
use warnings;
use strict;
while (<>){
    chomp;
  if (/(?[\d\D]*a)(?\s[\d\D]{4})/){
    print "$+{name1} $+{name2}\n";
    }
    }

例6:输出以空白结尾的行

#! /usr/bin/perl
use warnings;
use strict;
while (<>){
    chomp;
  if (/([\d\D]*\s\z)/){
    print "$1 m\n";
    }
    }

ps:

  1. 上面的方法尽管参考,方法肯定不止一个
  2. 如果跟我一样是菜鸟,请结合我的第之前的博客看如何运行这样的脚本。
  3. 博文内容为整理的《Perl语言入门》这本书,感谢这个书的作者Randal L等人的付出
个人公众号,比较懒,很少更新,可以在上面提问题:

更多精彩,请移步公众号阅读:

Sam avatar
About Sam
专注生物信息 专注转化医学