查看原文
其他

化腐朽为神奇,编程语言不可错过之---正则表达式

晨光 生信者言 2022-03-29

阅读用时:全文共3部分,约3500字,约6分钟

关键词:正则表达式、Perl语言




在前两次的Perl编程课程中,我们知道了perl常用的数据结构,哈希常用操作和子函数的相关理论知识,相信大家对于Perl语言有了一定的感性认识。现在,实操重点来了!


今天我们来一起学习一下Perl语言的实操必杀技能——正则表达式。


《Perl零零八速成系列》(共8节课)主要是面向无Perl编程经验或者Perl语言初学者,介绍Perl的基本知识和实用编程技巧。晨光与你一路,轻松点亮编程技能,一跃成为特工级的Perl编程牛人!

【前情回顾】

《Perl零零八速成系列---数据结构入门》

《Perl零零八速成系列---哈希和子函数》


【本节内容】

   正则表达式应用、基本概念、使用方法。


编程语言之杀手武器--正则表达式

不管选择哪门编程语言,正则表达式都是不得不学的杀手武器。而广受程序猿们喜爱的正则表达式基础标准--PCRE正则(Perl Compatible Regular Expression, Perl语言兼容正则表达式)就是最先在perl中整合和应用的哦。


系列开篇的时候跟大家介绍过,Perl就是为了文本处理而发明的“胶水语言”,从他的名字就可以看出来(估计大多人已经忘记了Perl的全名)--“实用报表提取语言”(Practical Extraction and Report Language)。与其它早期的程序语言相比,Perl比较显诸特征之一是

整合了C、sed、awk、shell 等的脚本语言特性,其中最重要就是正则表达式的集成啦!来自于Perl语言的PCRE正则(Philip Hazel用C编写)已被逐渐移植和应用到很多其他语言中,包括Tcl, Python, Microsoft’s .NET , Ruby, PHP, C/C++, Java等等。



什么是正则表达式


下面我们来看看,究竟什么是正则表达式呢?


大家平时在用Word等办公软件处理文本时,肯定会用到查找或替换字符的功能,这时大家的脑海里面也许会立马出现Ctrl+F的快捷键组合。同样的,在Perl语言里面,也有这种类似的操作。只不过它会以某种特定的方式进行查找和替换指定的字符串,这种特定的方式就是我们今天要学习的正则表达式。

 

正则表达式(regular expression) 描述了一种字符串匹配的模式 (pattern),可以用来检查一个串是否含有某种子串,将匹配的子串做替换或者从某个串中取出符合某个条件的子串等。



正则表达式的常用形式


Perl的正则表达式的三种形式,分别是:匹配,替换和转化。


匹配


匹配操作符 m// (可省略m)用于匹配一个字符串语句或者一个正则表达式,基本格式如下:


m/PATTERN/;

 

其中,PATTERN 为匹配模式,例如,我们可以用以下代码匹配标量 $bar 中的 "run":

 

#!/usr/bin/perl

 

$bar = "Iam runoob site. welcome to runoob site.";

if ($bar =~/run/){

   print "匹配成功\n";

}else{

   print "匹配失败\n";

}

 

运行结果:

匹配成功

 

PS: 这里的"=~"称为绑定操作符(bindingoperator),是为了告诉Perl,拿右边的模式来匹配左边的字符串,否则默认匹配$_(Perl特殊变量,我们在后面再做详细介绍)。

 

以上示例是在默认的匹配规则下进行匹配的,一般我们在进行模式匹配的时候,还会用到一些修饰符,常用的模式匹配修饰符如下表所示:

 

修饰符

描述

i

忽略模式中的大小写

m

多行模式

o

仅赋值一次

s

单行模式,"."匹配"\n"(默认不匹配)

x

忽略模式中的空白

g

全局匹配


比如,我们可以用 i 修饰符来忽略模式中的大小写,不仅可以匹配小写的run,也可以匹配大写的RUN:


#!/usr/bin/perl

 

$bar = "I am RUNOOB site. welcome to RUNOOB site.";

if ($bar =~/run/i){

   print "匹配成功\n";

}else{

   print "匹配失败\n";

}


运行结果:

匹配成功



替换


替换操作符 s/// 是匹配操作符的扩展,使用新的字符串替换指定的字符串。基本格式如下:

 

s/PATTERN/REPLACEMENT/;

 

其中,PATTERN 为匹配模式,REPLACEMENT为替换的字符串。例如,我们将以下字符串的 "google" 替换为 "runoob": 


#!/usr/bin/perl


$string ="welcome to google site.";

$string =~ s/google/runoob/;

 

print"$string\n";

 

运行结果:

welcome to runoob site.

 

同样,我们在进行替换操作的时候,也会用到一些修饰符,常用的替换操作修饰符如下表所示:


修饰符

描述

i

如果在修饰符中加上"i",则正则将会取消大小写敏感性,即"a""A" 是一样的。

m

默认的正则开始"^"和结束"$"只是对于正则字符串如果在修饰符中加上"m",那么开始和结束将会指字符串的每一行:每一行的开头就是"^",结尾就是"$"

o

表达式只执行一次。

s

如果在修饰符中加入"s",那么默认的"."代表除了换行符以外的任何字符将会变成任意字符,也就是包括换行符!

x

如果加上该修饰符,表达式中的空白字符将会被忽略,除非它已经被转义。

g

替换所有匹配的字符串。

e

替换字符串作为表达式

 

比如,我们可以用 g 修饰符,将$string 变量中的所有小写e字母都换成大写的E字母

 

#!/usr/bin/perl

 

$string ="welcome to google site.";

$string =~s/e/E/g;                                     #将e替换为E

 

print"$string\n";

 

运行结果:

wElcomE to googlE sitE.



转化


转化操作符 tr/// 用于搜索一个字符串,找出其中的各个元素,并用替换列表中的对应元素对它们进行替换。基本格式如下:

 

tr/SEARCHMENT/REPLACEMENT/

 

其中,SEARCHMENT 为搜索的字符串,REPLACEMENT为替换的字符串。tr///会把SEARCHMENT的第一个字符换成REPLACEMENT的第一个字符,SEARCHMENT的第二个字符换成REPLACEMENT的第二个字符,依此类推。例如,我们将变量 $string 中的所有小写字母转化为大写字母:

 

#!/usr/bin/perl

 

$string ='welcome to runoob site.';

$string =~tr/a-z/A-Z/;

 

print"$string\n";

 

运行结果:

WELCOME TO RUNOOB SITE.

 

没错,我们在进行转化操作的时候,也会用到一些修饰符,常用的转化操作修饰符如下表所示:

常见的转化操作修饰符及含义

修饰符

描述

c

转化所有未指定字符

d

删除所有指定字符

s

把多个相同的输出字符缩成一个


比如,我们可以使用修饰符 s 将变量 $string 重复的字符删除:

 

#!/usr/bin/perl

 

$string ='runoob';

$string =~tr/a-z/a-z/s;

 

print"$string\n";

 

运行结果:

runob

 

正则表达式的使用


在实际正则表达式的过程中,可能还需要运用一些规则和技巧,从而提高我们的匹配效率和准确性。


特殊字符


Perl 正则表达式中会经常用到一些特殊的字符,比如元字符、字符集和转义符等,它们都代表不同的含义。


元字符

为了扩大匹配的范围,引入了一些特殊的字符,成为元字符(metacharacter),它们在正则表达式中有着特殊的含义。

 

点号(.)是最常用的元字符之一,它能匹配除换行符(\n)以外的任意一个字符。例如,在模式/p.t/中,' . '用于匹配任何单个字符。这个模式用于匹配pot、pat、pit、carpet、python和pup_tent。' . ' 要求存在一个字符,但是不能有更多的字符。因此,该模式不能与apt相匹配(p与t之间没有任何字符),也不能与expect相匹配(pt之间的字符太多)。

 

星号(*)是外一个常用的元字符,它是用来匹配前面的条目零次或者多次的。因此,/fred*/能够匹配fred后面零次或者多次重复的字母d。

 

加号(+)用于使前面的字符至少匹配一次或多次。因此,/do+g / 将能够与下面的字符串匹配:hotdog、doogie,但是不能匹配badge、doofus。

 

常见的元字符及含义

表达式

描述

.

匹配除换行符以外的所有字符

x?

匹配 0 次或一次 x 字符串

x*

匹配 0 次或多次 x 字符串,但匹配可能的最少次数

x+

匹配 1 次或多次 x 字符串,但匹配可能的最少次数

.*

匹配 0 次或多次的任何字符

.+

匹配 1 次或多次的任何字符


字符集

字符集(character class),指的是一组可能出现的字符,通过写在方括号([])内表示。它只匹配单个字符,但可以是字符集中列出的任何一个,常见的字符集如下表所示:

 

常见的字符集及含义

表达式

描述

[]

匹配符合 [] 内的字符

[^]

匹配不符合 [] 内的字符

[0-9]

匹配所有数字字符

[a-z]

匹配所有小写字母字符

[^0-9]

匹配所有非数字字符

[^a-z]

匹配所有非小写字母字符

^

匹配字符开头的字符

$

匹配字符结尾的字符


转义符

正如我们在前面课程里面所介绍的换行符(\n),反斜线(\)后面跟上不同字符,可以表示不同的意义,一般我们把这种借助反斜线组合表示特殊字符的方法称作反斜线转义。常见的转义符以及含义如下表所示:

 

常见的转义符及含义

表达式

描述

\d

匹配一个数字的字符, [0-9] 语法一样

\D

非数字,其他同 \d

\w

英文字母或数字的字符串, [a-zA-Z0-9_] 语法一样

\W

非英文字母或数字的字符串, [^a-zA-Z0-9_] 语法一样

\s

空格, [\n\t\r\f] 语法一样

\S

非空格, [^\n\t\r\f] 语法一样

\b

匹配以英文字母,数字为边界的字符串

\B

匹配不以英文字母,数值为边界的字符串


模式分组


在正则表达式中,圆括号((),或称小括号)的作用是对字符串分组。因此圆括号也是一种元字符。举例来说,模式/fred+/会匹配像fredd、fredddd、fredddddd这样的字符串,而模式/(fred)+/会匹配像fredfred、fredfredfred这样的字符串。因此圆括号的作用是将特定的字符串进行分组,从而按照特定的规则进行匹配。


变量捕获


圆括号除了具有模式分组的功能,还能够触发正则表达式引擎捕获匹配到的字符串,捕获组会把匹配圆括号中模式的字符串保存到相应的地方。一般这些捕获到的字符串会根据括号的多少按照(左括号的)顺序,依次被储存在$1、$2、$3等特殊变量中。例如:

 

#!/usr/bin/perl

 

$string="Hello there,neighbor";

if($string=~/\s([a-zA-Z]+),/){                #捕获空格(\s)和逗号(,)的之间的字符串

print"the word was: $1\n";

}

 

运行结果:

the word was: there


择一匹配

 

竖线(|)通常可以读成"或",表示要么匹配左边的内容,要么匹配右边的内容。因此,/fred|barney|betty/能匹配任何含有fred或者barney或者betty的字符串。例如:

 

#!/usr/bin/perl

 

while(<>){                                       #每次读一行输入

chomp;                                     #去掉末尾的换行符,默认为\n

if(/(geneA|geneB)/){                  #匹配geneA或geneB

print "Matched: $1\n";

}else{

print "No match: $_\n";

}

}

 

如果我们将以上代码保存在test.pl里面,然后将geneA、geneB、geneC按行保存到gene.list,在终端运行命令:

 

perl test.pl gene.list

 

将得到结果:

 

Matched: geneA

Matched: geneB

No match:geneC

 

PS: 这里的 <> 称为钻石操作符,是行输入操作符的特例,可以让Perl从用户指定的位置逐行读取。读取到的内容被保存在Perl的特殊变量$_中,直到下一行被读取并且覆盖原内容。


通用量词


模式中的量词(quantifier)代表前面条目的重复次数。除了前面介绍的表示次数的元字符(*、+、?),还可以用花括号({})来表示具体的重复次数范围。如果以正整数m、n (m<n)表示重复次数,那么可以用以下方式来指定重复次数的范围: 


通用量词及含义

表达式

描述

{m}

匹配刚好是m个的指定字符串

{m,n}

匹配在m个以上,n个以下的指定字符串

{m,}

匹配m个以上的指定字符串


例如,模式/a{5,15}/会匹配重复出现5~15次的字符a,而模式/fred{3,}/会匹配重复出现3次或3次以上的字符fred。


本文尽量精简地介绍了Perl语言中正则表达式的使用,并配上简单的示例供大家练习巩固。由于篇幅有限,难以深入展开说明,谨以此文,送与初入门Perl语言的朋友们。

 

正则表达式,你了解了吗?实际的编程工作中,正则表达式是所有程序猿(包括常用语言为Python 、Java等的宝宝们)绕不过的一道坎。下期,我们结合NGS测序中数据的常见问题,将会为大家插播一期实例精讲!


真正的实战,就在下期!干货不容错过~

 

参考资料:

《Perl语言入门第六版(中文版)》

http://www.runoob.com/perl/perl-tutorial.html

http://www.runoob.com/try/runcode.phpfilename=HelloWorld&type=perl




【完】


作者原创作品,未经授权禁止转载!


扫码关注,获取更多精彩内容

喜马拉雅FM搜索并订阅:生信者言;收听内容:

《一分钟听懂NGS基础概念》,让生信分析不再遥不可及

《亲爱的姑娘,你值得被温柔以待》,11个真实的人物故事

《众病之王:癌症传》,一起聆听人类对抗癌症的斗争史

回复文字:果然科学,看一篇好玩的科普文。

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存