目录
基本组成
正则表达式描述了一种字符串的匹配模式,通过这个模式在特定的函数中对字符串进行匹配、查找、替换以及分割等操作。
正则表达式作为一个匹配的模板,是由定界符,原子(普通字符,例如a-z)、元字符(有特殊功能的字符,例如*、+、?等),以及模式修正符等部分组成的文字模式。
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<?php /** * 目标: 把座位号全都找出来 */ // 要处理的文本 $subject = '小明的座位号:A950,座机号:950001;小红的座位号:A951,座机号:950002;小米的座位号:A952,座机号:950003'; // 正则表达式 $pattern = '/A\d+/i'; preg_match_all($pattern, $subject, $matches); echo '<pre/>'; var_dump($matches); |
定界符
除了字母、数字和反斜线以外的字符皆可为定界符。如果没有特殊要求,一般使用/
作为定界符。定界符是成对的,有开始符号,也有结束符号。
/A\d+/i
:合法。以/
作为定界符,且成对出现。
|A\d+|i
:合法。以|
作为定界符,且成对出现。
{A\d+}i
:合法。以{
作为定界符,且成对出现。
/A\d+i
:不合法。以/
作为定界符,但是缺少/
作为结尾。
A\d+/i
:不合法。以/
作为定界符,但是缺少/
作为开始。
原子(普通字符)
原子是那些所有打印字符和非打印字符(空格、回车等看不到的)。特殊字符要变成原子需要在前面加入反斜杠(\
) 例如:\*
、 \?
等。简单地说,能够在正则表达式中单独使用的字符就可称为原子。
将其划分为五类
普通字符作为原子
普通字符是编写正则表达式时最常见的原子,包括所有的大写和小写字母字符、所有数字等,例如:a-z、A-Z、0-9。
非打印字符(看不到的)
\cx
:匹配control + 控制字符
,就是说 匹配由x
指明的控制字符。比如:
\cI
匹配control + I
,等价于\t
,\cJ
匹配control + J
,等价于\n
,\cM
匹配control + M
,等价于\r
\f
:匹配一个换页符。等价于\x0c
和\cL
。
\n
:匹配一个换行符。等价于\x0a
和\cJ
。
\r
:匹配一个回车符。等价于\x0d
和\cM
。
\t
:匹配一个制表符。等价于\x09
和\cI
。
\v
:匹配一个垂直制表符。等价于\x0b
和\cK
。
通用字符类型(也称:预定义类)
前面介绍的原子,都是一个原子只能匹配一个字符。但是有时候我们需要一个原子可以匹配一类字符。在正则表达式中可以直接使用一些代表范围的原子。
.
:匹配除了回车符和换行符之外的所有字符。等价于[^\r\n]
\d
: 匹配数字字符。等价于[0-9]
。
\D
: 匹配非数字字符。等价于[^0-9]
。
\w
:匹配任意一个数字、字母、下划线,等价于[0-9a-zA-Z_]
。
\W
:匹配除数字、字母、下划线以外的任意一个字符,等价于[^0-9a-zA-Z_]
。
\s
:匹配任意一个空白字符,等价于[\f\t\n\v\r]
。
\S
:匹配除空白字符以外的任何一个字符,等价于[^\t\f\n\v\r]
。
原子表(也称:字符类、字符集合)
我们需要自定义一类原子,比如说奇数(1,3,5,7,9),所以这时候需要我们自定义一类原子(称之为类原子)。
使用原子表[]
就可以定义一组彼此平等的原子,只能匹配原子表中一个字符。
/[apj]sp/
: 可以匹配asp、jsp、psp
三种,从原子表中仅选择一个作为原子。
字符类取反
使用元字符’^
‘创建 反向类/负向类。
反向类的意思是不属于类的内容,例如:
/[^apj]sp/
: 可以匹配除了asp、PSP、jsp
三种以外的字符串,如xsp,ysp,zsp
等。
范围类
正则表达式给我们提供了范围类,我们可以使用’-
‘来连接两个字符。如:[a-z]
,表示从a到z的任意字符,这是一个闭区间,包含 a 和 z 本身。
/0[xX][0-9a-fA-F]/
:可以匹配一个简单的十六进制数,如0x2f、0X3AE或0x4aB等。
一些特殊字符和元字符作为原子
在正则表达式中,任何一个符号都可以作为原子使用,但如果该符号在正则表达式中有特殊意义,可以使用转义字符“\
”取消它的特殊意义,作为一个普通字符使用。
如 “\. \* \+ \? \( \<\>
“。
元字符(特殊字符)
1、元字符是用于构建正则表达式的具有特殊含义的字符,如*
、+
、?
等。
2、元字符不能单独出现,必须用来修饰原子。
3、如果要在正则表达式中使用包含元字符本身,为了使其失去特殊含义,则必须在前面加上\
进行转义。
边界(也称:定位符)
^
:以xxx开始。
$
:以xxx结束。
\b
:单词边界。
\B
:非单词边界。
例如:
有一个字符串 “this is a test”,使用边界限制如下:
“/^this/
“:匹配此字符是否以字符串”this”开始的,匹配成功。
“/test$/
“:匹配此字符是否以字符串”test”结束的,匹配成功。
“/\bis\b/
“:匹配此字符串中是否含有单词”is”,因为在字符串”is”两边都需要有边界。
“/\Bis\b/
“:查找字符串”is”时,左边不能有边界而右边必须右边界,如”this”匹配成功。
量词(也称:限定符)
?
:出现零次或一次(最多出现一次)。
+
:出现一次或者多次(至少出现一次)。
*
:出现零次或者多次(任意次)。
{n}
:出现n次。
{n,m}
:出现n到m次。
{n,}
:至少出现n次。
选择符
竖线字符”|
“用来分隔多选一模式,在正则表达式中匹配两个或更多的选择之一。
因|
的优先级是最低的,所以应在最后考虑其功能。
例如:LAMP | J2EE
表示匹配LAMP,也可以匹配J2EE,由于|
其优先级最低,所以并不表示匹配’LAMP2EE’或者’LAMJEE’。
也可以像这样使用 “/Linux|Apache|MySQL|PHP/
“,表示可以从中任意匹配一组。
分组符号(也称:子组)
子组通过()
分隔界定,并且它们可以嵌套。子组具有两个作用:
1、 将可选分支局部化;
2、 将子组设定为捕获子组。
分组匹配的内容可以在后续的正则中重复使用,只需要指定分组的序号即可。分组的序号是从左往右以此递增的。
1 2 3 4 5 6 |
<?php $subject = 'hello'; $pattern = '/(\w{2})(\w{3})/'; preg_match_all($pattern, $subject, $matches); |
输出结果:
1 |
['he','llo'] |
由例子中可以看出这里的()
分组捕获的匹配内容。
非捕获分组,在分组开头添加?:
,表示该分组对应内容为非捕获分组,这个分组不捕获。
1 2 3 4 |
<?php $subject = 'hello'; $pattern = '/(?:\w{2})(\w{3})/'; |
反向引用(也称:后向引用)
反向引用需要使用到分组。
使用分组符号()
,捕获到匹配的分组结果,这些分组都是自动编号(从1自动递增)。
反向引用,使用\n
(如:\1
)或$n
(如:$1
),来获取对应编号的分组。
如:\1
,\2
等
\1
:表示的是引用第一次匹配到的()括起来的部分。\2
:表示的是引用第二次匹配到的()括起来的部分。
贪婪/懒惰
贪婪量词,是先吃尽所有字符,然后再一个一个地吐出来,直接匹配成功为止。(匹配顺序:文本头 <- 文本尾) 懒惰量词,是从头开始一个字符一个字符地吃,直接匹配成功为止。(匹配顺序:文本头 -> 文本尾)
懒惰是从左边一个一个地吃直到匹配为止,不加 ?
的是一口吃掉整个字符串,然后从最后一个一个地吐出来直到匹配为止。
例子:
贪婪模式
字符串
a=b=b===
a.*b
将匹配满足条件最长的字符串 a=b=b
工作方式:
首先将:a=b=b=== 全部吃掉,从右边一个一个地吐出来
a=b=b=== 不匹配,吐出一字符
a=b=b== 不匹配,再吐出一字符
a=b=b= 不匹配,再吐出一字符
a=b=b 匹配了,结束。如果再不匹配继续吐,直到没有字符了,匹配失败
懒惰模式
a.*?
将匹配满足条件最短的字符串 a=====b
工作方式:
从左边一个一个地吃掉字符
a 不能匹配表达式,继续吃
a= 不能匹配表达式,继续吃
a== 不能匹配表达式,继续吃
a=== 不能匹配表达式,继续吃
a==== 不能匹配表达式,继续吃
a===== 不能匹配表达式,继续吃
a=====b 呵呵,终于能匹配表达式了,匹配结束,匹配位置留于字符 b 后面,继续其他的匹配。如果不能匹配则一个一个地吃掉整个字符串直到吃完为止若还没有匹配则匹配失败。
懒惰限定符/贪婪限定符
?
表示懒惰限定符。*
表示贪婪限定符。
以下是懒惰限定符的组合使用:
*?
:重复任意次,但尽可能少重复。
+?
:重复1次或更多次,但尽可能少重复。
??
:重复0次或1次,但尽可能少重复。
{n,m}?
:重复n到m次,但尽可能少重复。
{n,}?
:重复n次以上,但尽可能少重复。
前瞻(也称:断言)
前瞻/后顾
对于正则表达式引擎来说,因为它是从文本头部向尾部开始解析的,因此对于文本尾部方向,因为这个时候正则引擎还没走到那块,所以他是正则的前方。而对文本头部方向,因为正则引擎已经走过了那一块地方,所以他是正则的前方。如下图所示:
正向/负向
包含断言assert部分,称为正向;不包含断言assert部分,称为负向。
exp(?=assert)
: 正向前瞻。从左往右匹配,匹配到exp,且exp前面必须是断言assert,才算成功。
exp(?!assert)
:负向前瞻。从左往右匹配,匹配到exp,且exp前面必须不是断言assert,才算成功。
exp(?<=assert)
:正向后顾。从左往右匹配,匹配到exp,且exp后面必须是断言assert,才算成功。
exp(?<!assert)
:负向后顾。从左往右匹配,匹配到exp,且exp后面必须不是断言assert,才算成功。
例子:可参考 这里。
模式修正符
模式修正符在正则表达式定界符之外使用(最后一个斜线”/”之后)。模式修正符可以调整正则表达式的解释,扩展了正则表达式在匹配、替换等操作时的某些功能;而且模式修正符可以组合使用,更增强了正则表达式处理能力。
i
:不区分大小写。
g
:进行全局匹配,即对字符串进行全文匹配,直到字符串遍历结束。
m
: 将字符串视为多行。那么开始和结束将会指字符串的每一行,每一行的开头就是”^”,结尾就是”$”。
s
:如果设定了次修正符,则模式中的圆点元字符”.
“匹配所有的字符,包括换行符。即将字符串视为单行,换行符作为普通字符看待。
x
:模式中的空白忽略不计,除非它已经被转义。
e
:只有在preg_replace()函数中,在替换字符串对逆向引用做正常的替换,将其作为PHP代码求值,并且其结果来替换所搜索的字符串。
U
:本修正符反转了匹配数量的值使其使其不是默认的重复,而变成在后面跟上”?”才变得重复。也可以通过在模式中设定(U)修正符或者数量符之后跟一个问号”?”(例如.*?)来使用此选项。
D
:模式中的美元元字符仅匹配目标字符串的结尾。没有此选项时,如果最后一个字符是换行符,则美元符号也会匹配次字符之前的内容。如果设定了m修正符,则忽略此选项。