Perl学习笔记9——正则表达式(上)

正则表达式简介

Perl最重要的一大特色就是对正则表达式的强力支持,这些支持提供了强大且灵活的字符串处理能力。正则表达式实质上是Perl内嵌的,自成一体的微型编程语言。其不只是Perl的一部分,在很多其他语言中也都有应用。

Perl中,正则表达式通常简称为模式。正则表达式是具有一定特征的一个模板,任意的字符串都可以与其匹配,且只有两种匹配结果:匹配或不匹配。所以正则表达式常用于布尔上下文中,从而使其匹配结果作为布尔值返回。

模式匹配操作符

Perl中,使用模式匹配操作符“m//”进行模式匹配操作。完整的模式匹配操作符包括关键词m其后的定界符。类似于qw简写,可以选用任意成对且合适的符号作为定界符,且当以斜线作为定界符时,可以省略关键字m。

当没有为m//指定匹配的内容时,其会默认匹配$_的内容。下例是一个简单的模式匹配:

$_="abcd";

if(/a/){print'T'}else{print'F'}    #模式/a/会在$_中匹配a,即$_中是否出现了a,结果是真,所以输出T。由于以斜线作为定界符,所以省略了斜线前的m

模式中的内插与反斜线转义

所有在双引号引起的字符串中可以使用的技巧,都可以在模式表达式中使用。最主要的即反斜线转义和模式内插。例:

print'T'if/\n/;    #在模式中使用反斜线转义,匹配换行符

print'T'if/$n/;    #在模式中使用变量内插,匹配$n的内容

绑定操作符

默认情况下m//的操作对象是$_的内容。而如果要为模式指定匹配的对象,就可以使用绑定操作符“=~”。例:

print'T'if$n=~/a/;    #模式用于匹配$n的内容

绑定操作符是一个优先级相当高的操作符,所以在一般的表达式中,如果不使用括号限定,那么就会优先进行模式匹配。例:

$_=$n=~/a/;    #先进行匹配,再将匹配结果返回并赋值给$_(返回的结果为1或undef,默认布尔值)

元字符初步

在模式中有一类特殊字符,一般情况下其不代表本身,而是有着特殊的含义,这一类字符就称为元字符。在下文中会出现各种元字符的运用。这里将常见的元字符列举如下:

点号“.”

反斜线“\”

量词“*”、“+”、“?”

小括号“( )”

中括号“[ ]”

竖线“|”

在模式中,点号又称通配符,可以用于匹配任意一个非换行符字符。例:

/a../     #可匹配aaa、abc等

/a..d/    #可匹配abcd、aaad等

类似于双引号圈引的字符串,在模式中反斜线可用于反斜线转义,也可用于将特殊的元字符转义为其自身。例:

/\n/   #匹配换行符

/\./   #匹配点号

/\\/   #匹配反斜线自身

量词初步

在模式中,量词可以用于重复量词前的某一部分内容。不同的量词代表前面条目不同的的重复次数。常用的量词主要有三种:星号“*”、加号“+”和问号“?”。星号量词可以将其前面的条目重复零次至多次。也就是说,星号前面的条目可以不出现,也可以重复出现任意多次。类似于星号量词,加号量词可以将其前面的条目重复一至多次。也就是说,加号前面的条目必须至少出现一次才能匹配。而问号量词的限定更为严格,其前面的条目只能出现零次或一次才能匹配,其他情况均不能匹配。例:

/a*b/    #可匹配b、ab、aaab等

/a+b/    #可匹配ab、aaab等,但不能匹配b

/a?b/    #可匹配b或ab

量词很常见的用法就是与通配符连用,可以匹配多个任意字符。例:

/a.*b/    #匹配a与b之间任意多个字符,可匹配ab、aaab等

/a.+b/    #匹配a与b之间至少一个字符,可匹配a-b、aaab等,但不能匹配ab

/a.?b/    #匹配a与b之间至多一个字符,可匹配ab、a-b等,但不能匹配abbb等

通用量词

如果上文中的三个常用量词都不符合需要,还可以使用通用量词。通用量词用于说明具体的重复次数范围,其由一对花括号和其中的数字组成,数字可以为一个或两个,中间以逗号隔开,用以说明重复次数范围。而如果省略第二个数字但有逗号,则表示重复次数无上限。例:

/a{3}/      #重复三次,只能匹配aaa

/a{3,5}/    #可匹配重复次数三次至五次的a

/a{3,}/     #可匹配重复至少三次的a

常用的三个量词实质上就是通用量词的简写:

{0,}     #相当于*

{1,}     #相当于+

{0,1}    #相当于?

模式分组

在正则表达式中,小括号作为一种元字符,其作用为对模式表达式的内容进行分组,从而对这一组内容进行整体上的处理。最常见的如对一组内容整体上使用量词,而不是像上文那样仅对量词前的一个字符使用。模式分组实质上是利用了小括号在模式中的最高优先级这一性质(详见“优先级”),从而使分组中的内容形成一个整体,以实现各种整体上的操作。例:

/ab+/     #量词仅对其前面的b起作用,可匹配abbb等

/(ab)+/    #使用模式分组,量词对(ab)起作用,可匹配ababab等

择一匹配

在正则表达式中,有一个类似于逻辑或操作符“||”的符号“|”,称为择一竖线,其可用于择一匹配。择一匹配的意思即择一竖线两边的内容都可以尝试进行匹配,也就是说,如果左边的内容匹配失败,还可以尝试匹配右边的内容。择一竖线是模式匹配中优先级最低的一个元字符,所以使用时应注意在需要的时候使用模式分组。例:

/a|b|c/     #匹配a或b或c

/a(b|c)d/    #匹配abd或acd

/ab|cd/     #匹配ab或cd

字符集

前文提到,一个点号可以用来代表任意一个非换行符字符。而如果需要匹配的可能字符种类没有这么宽泛,而是一组特定的字符,比如需要匹配任意一个数字,或是小写字母等,就可以使用字符集。

字符集书写在一对方括号内,表示所有可能出现的字符。字符之间不需要任何分隔。例:

/[abc]/     #一个字符集,可匹配abc中任意一个字符一次

/[123]+/    #字符集与量词连用,匹配123中任意一个字符至少一次

当字符集内的字符是一串连续字符时,如26个小写字母或0到9这十个数字等,就可以使用连字符表示始末范围,这样可以大大简化字符集的书写。例:

[0-9]      #所有的数字构成的字符集

[a-zA-Z]    #所有的大小写字母构成的字符集

在字符集中,有时候还需要构造反义字符集,即除了字符集中的字符,其他都匹配。可以在字符集开头的地方加上脱字符“^”来构造反义字符集。例:

/[^0-9]/      #匹配除了10个数字以外的字符一次

/[^a-zA-Z]/    #匹配除了大小写字母以外的字符一次

某些字符集的出现频率非常高,所以Perl为其设定了简写。字符集简写均由反斜线后接一个字母组成。常用的字符集简写及其一般性解释如下:

[\w]   #单词字符集,一般相当于[a-zA-Z0-9_],即所有大小写字母加上10个数字和下划线

[\d]   #数字字符集,一般相当于[0-9]

[\s]   #空白符字符集,一般可匹配空格,换行符,制表符等空白符

简写的字符集也能构造反义字符集,且无需使用脱字符,直接将小写字母换成其对应的大写字母即可。例:

[\W]   [\D]    [\S]    #三种简写字符集的反义写法

在不引起歧义的情况下,字符集的中括号常可以省略,从而简化书写。例:

/\w+/    #简写的单词字符集与量词连用

模式匹配修饰符初步

Perl中提供了一系列模式匹配修饰符,又称为副词或标志。其可以改变一些默认的匹配行为,从而对模式匹配起到修饰的作用。模式匹配修饰符书写在模式表达式末尾定界符的后面,其都是由一个字母构成。下文列举了一些常用的修饰符及其作用,还有其他的一些修饰符会在后文中陆续提及:

/i修饰符:可进行大小写无关的匹配,即模式表达式中的字母可匹配小写也可匹配大写。例:

/abc/i    #进行大小写无关的匹配,可匹配abc、ABC、Abc等

/s修饰符:可增大通配符匹配范围,使其能够匹配到换行符,多用于含有多行的字符串匹配。例:

/a.*b/s    #增大点号匹配范围,使其能够匹配到换行符。可匹配"a\nb"等

/x修饰符:允许在模式中随意加入空白符,使其更易阅读和理解,多用于复杂模式中。也就是说,使用了/x修饰符后,就可以随意在模式中加入空格或者换行符来分隔,而Perl会将其忽略。此时如果要表示换行符或者空格本身,可以使用反斜线转义,或使用空白字符集[\s]来匹配空白符。例:

/a b/x               #在模式中忽略空格,相当于/ab/

/a

b/x                 #在模式中忽略换行符,相当于/ab/

/a\ b/x    /a\nb/x   #使用反斜线转义表示空格和换行符本身

如果要在一个模式中使用多个修饰符,直接将多个修饰符一起写在末尾定界符之后即可,先后顺序不限。例:

/a b/isx    #同时使用三个修饰符

模式替换操作符

正则表达式不仅可以用于匹配文本,还可以用于直接修改文本。可以使用模式替换操作符“s///”来对文本进行匹配并修改。s///操作的字符串一般要求存储于变量中,而实际上,如果对一个未存储于变量中的字符串进行修改,那么修改的结果也是不能够存储的,所以这样做没有实际意义。

与m//类似,s///由关键词s及其后面的定界符构成。第一对定界符内为一个正则表达式,第二对定界符内为用于替换的字符串。s///会先对给定字符串进行模式匹配,如果匹配成功,就会将全部的匹配内容替换成第二对定界符中的内容,而如果匹配失败,则不会有任何效果。s///在未绑定变量时默认的操作对象也是$_中的内容,可使用绑定操作符为其指定一个操作对象。例:

s/@/>/;    #在$_中匹配@字符,如果匹配成功,则将其替换为>

与m//类似,s///中也可使用变量内插、反斜线转义等功能。在默认情况下,s///只会对其匹配到的第一个可替换部分进行替换,然后就结束语句。也就是说,即使还有其他可以替换的部分,在默认情况下s///也只会进行一次替换。例:

$_=aaa;

s/a/b/;    #此时$_会被替换为baa

s///自身返回的是成功替换的次数,在没有修饰符的情况下,返回值只能为0或1,即成功替换的次数只能为0或1次。也可以将其返回值当作布尔值使用,用来表示替换操作是否成功进行。例:

print while s/a/b/;    #将s///用在布尔上下文中,进行循环替换

while(s/a/b/){}       #借助while循环进行多次替换(仅作示例,实际上无需这种写法,详见“全局替换”)

上文提到,s///的关键词s后面也是定界符,也就是说,s后面的符号可以任意选用。但由于s///后面的定界符不止一对,所以使用上较m//有所区别。如果s///的定界符选用的是类似于斜线这样的非成对字符,即没有左右之分的定界符,那么用法就同斜线一样,使用三个即可。而如果选用的定界符是类似于花括号这样的分左右的成对字符,那么定界符就需要使用两对,一对包住模式,另一对包住替换字符串。且在这种使用两对定界符的情况下,这两对定界符可以分别选用不同的符号,可以成对,也可以非成对。依据需求选用即可。例:

s#a#b#;    #使用非成对字符井号作为定界符

s{a}{b};     #使用成对的花括号作为定界符

s\b\;         #定界符混合使用

s/a/b/;     #上面的三个语句都和此写法没有任何区别

全局替换

上文提到,在默认情况下,s///最多只能进行一次替换。而如果想让s///进行全部可能的替换,就可以使用全局替换修饰符“/g”。

/g修饰符可以让s///进行所有可能且不重复的替换,这里的不重复是指:s///的每一次模式匹配都会从最近一次替换操作结束位点的下一个字符开始,从而避免对已被替换的内容进行重复替换。例:

s/a/b/g;    #对$_进行全局替换,将所有匹配到的a替换为b

s///的修饰符用法和m//一致,都可以同时使用多个修饰符,且直接将多个修饰符一起写在s///的最后一个定界符之后即可,顺序不限。例:

s/a/b/gix;    #同时使用三个修饰符

无损替换

上文提到,在默认情况下,s///会直接修改变量的内容,而其自身返回的是成功替换的次数。而如果需要保留原字符串的内容,且将替换后的结果作为s///的返回值返回,就可以使用无损替换修饰符“/r”。

/r修饰符可以让s///的返回值由成功替换的次数变为替换结果,并且不对原字符串的内容做任何修改,从而实现无损替换。例:

$n=s/a/b/gr;    #对$_进行无损的全局替换,并将结果返回并赋值给$n,$_中的内容不会改变


樱雨楼

完成于2016.1.19

最后修改于2016.2.1

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容

  • 捕获组与反向引用 在正则表达式中,圆括号的一大作用是进行模式分组,而其还有另一个非常重要的作用,即定义捕获组。捕获...
    樱雨楼阅读 1,521评论 0 0
  • Python中的正则表达式(re) import rere.match #从开始位置开始匹配,如果开头没有则无re...
    BigJeffWang阅读 6,931评论 0 99
  • 从匹配中返回值 Match 对象 成功的匹配总是返回一个 Match 对象, 这个对象通常也被放进 $/ 中, (...
    焉知非鱼阅读 1,699评论 0 1
  • 官网 中文版本 好的网站 Content-type: text/htmlBASH Section: User ...
    不排版阅读 4,310评论 0 5
  • 初衷:看了很多视频、文章,最后却通通忘记了,别人的知识依旧是别人的,自己却什么都没获得。此系列文章旨在加深自己的印...
    DCbryant阅读 3,896评论 0 20