PHP正则表达式简介
1. 什么是正则表达式
正则表达式(regular expression)是一组用来匹配模式的字符串,通过定义规则,来实现字符串的查找、替换和验证。举个例子,你可以用正则表达式来查找一段字符串中的数字;再比如说,可以将字符串中符合规则的子串替换成另外的字符;又或者,用正则表达式来验证用户输入的密码是否符合某种规范(比如长度6-8个字符,同时包含大小写字母和数字)。
不同语言的正则表达式有不同的语法,不过大体上都有普通字符、限定符、元字符、转义符号、修饰符等概念,下面简单讲解一下PHP中的正则表达式。
2.PHP的正则表达式
我们先看看一个简单的模式,/https?/i
,其中,/
表示分隔符,两个/
中间的部分就是匹配的规则。最后面的i
是修饰符,在这里表示不匹分大小写,修饰符不是必需的。https
属于普通符号,\d
属于元字符,代表着数字0-9
2.1 分隔符
常用的分隔符是正斜线(/),但除了字母、数字、空格、以及反斜线(\)外,其他符号都可以用作分隔符。比如:
/http:\/\//
#http:\\#
都是合法的PHP模式。可以看到,在模式中使用到分隔符的时候,必须用转义字符进行转义。所以如果分隔符经常在正则模式内出现,可以使用其他分隔符以便提高可读性。
2.2 元字符
正则表达式的强大源于它可以在模式中拥有选择和重复的能力。一些字符被赋予特殊的涵义,这些字符就是元字符。PHP中的元字符有以下这些:
元字符 | 说明 |
---|---|
\ | 用于转义 |
^ | 匹配输入字符串的开始位置(或在多行模式下是行首) |
$ | 匹配输入字符串的结束位置(或在多行模式下是行尾) |
. | 匹配除换行符外的任何字符(默认) |
[ | 开始字符类定义 |
] | 结束字符类定义 |
| | 开始一个可选分支 |
( | 子组的开始标记 |
) | 子组的结束标记 |
? | 作为量词,表示 0 次或 1 次匹配。位于量词后面用于改变量词的贪婪特性。 |
* | 量词,0 次或多次匹配 |
+ | 量词,1 次或多次匹配 |
{ | 自定义量词开始标记 |
} | 自定义量词结束标记 |
在模式中,方括号[]
内的部分称为字符类,表示一些字符的合集。在这一部分,有另外的元字符定义:
元字符 | 说明 |
---|---|
|转义字符 | |
^ | 仅在作为第一个字符(方括号内)时,表明字符类取反 |
- | 标记字符范围 |
举个例子,/[a-z0-9,]/
表示所有小写字母和数字和逗号,[^a-z,]
表示除了小写字母和逗号之外的所有字符。
2.3 转义序列(反斜线)
反斜线\
通常的作用是转义,即表明取消该字符所代表的特殊涵义。比如上面提到的元字符*
,如果要匹配到星号*
,而不是表示0或多次匹配,则可以写成\*
,反斜线在这里就起到转义作用。
\
的第二个作用,是用来表示非打印字符,比如换行符\n
,制表符\t
等等。
对于\
的另一个重要的作用,则是用来描述特定的字符类:
字符 | 说明 |
---|---|
\d | 任意十进制数字 |
\D | 任意非十进制数字 |
\w | 任意单词字符(字母、数字、下划线) |
\W | 任意非单词字符 |
\s | 任意空白字符 |
\S | 任意非空白字符 |
2.4 量词
量词用于表示重复多次匹配,格式为{数字1,数字2}
,其中两个数值都必须小于 65536, 并且第一个数字必须小于等于第二个。如果数字2被省略{数字1,}
,则表示没有大限。如果连逗号都被省略{数字1}
,则表示确定次数的匹配。
举例说明,/a{3,8}/
表示匹配连续的3-8个a,/a{3,}/
表示匹配大于等于3个a,/a{3}/
表示匹配刚好3个a。常用的*
,+
,?
分别等价于{0,}
,{1,}
,{0,1}
默认情况下,量词都是“贪婪”的,也就是说, 它们会在不导致模式匹配失败的前提下,尽可能多的匹配字符。然而,如果一个量词紧跟着一个 ?(问号) 标记,它就会成为懒惰(非贪婪)模式, 它不再尽可能多的匹配,而是尽可能少的匹配。
例如,/<(.*)>/
去匹配<head></head>
会匹配到整个字符串,.*
捕获出来的是head></head
,而/<(.*?)>/
去匹配<head></head>
只会匹配到前面的<head>
,.*?
捕获到的是head
。
2.5 修饰符
在分隔符后面,可以加修饰符,常用的修饰符有:
符号 | 说明 |
---|---|
i | 不区分大小写 |
s | 模式中的圆点符号. 匹配所有的字符,包括换行符 |
m | 匹配多行,使^ 、$ 分别匹配到每一行的行首和行尾 |
例如/abc/i
可以匹配到abc
,Abc
,ABC
等字符串。
2.6 子组和可选路径以及后向引用
圆括号()
中的部分即为子组,可以用来捕获其中的内容,也可以在其中加上|
形成可选路径。比如/cat(abc)+/
中abc
为一个整体,可以匹配到catabc
,catabcabc
等。如果没有括号的话,/catabc+/
就只能匹配到catabccc
之类的字符串。再比如,/cat(abc|def)/
中,|
将子组分成两个可选的部分,能匹配到catabc
,catdef
两个字符串。值得注意的是,|
可以为空的字符串,比如/cat(abc|def|)/
可以匹配到catabc
,catdef
,cat
三个字符串。
圆括号()
中匹配到的内容,可以在后面通过反斜杠+数字
的方式进行引用,这称之为后向引用。举例说明,/(\d{2})=\1/
可以匹配到13=13
,/(\d{2})(\d{2})=\2\1/
可以匹配到1234=3412
,这里面\1
,\2
表示前面捕获到的第1、第2个子组。
如果想要在括号里只表示分组,而不需要捕获,可以在左括号后面紧跟字符串 ?:
,例如/(?:\d{2})(\d{2})=\1/
中只会捕获到后面括号的一组内容,所以后面只能跟\1
,可以匹配到1234=34
这样的字符串。
3. PHP的正则表达式的函数
3.1 preg_match
preg_match
用于执行匹配正则表达式。其函数原型为:
1 |
|
参数说明如下:
- pattern : 要搜索的模式,字符串类型。
- subject : 输入字符串。
- matches : 可选参数,会被填充为搜索结果。其中
matches[0]
将包含完整模式匹配到的文本,matches[1]
将包含第一个捕获子组匹配到的文本,以此类推。 - flags : 可选参数,$flags 可以被设置为 PREG_OFFSET_CAPTURE,如果传递了这个标记,对于每一个出现的匹配,返回时都会附加上字符串偏移量(相对于目标字符串的);
- offset : 可选参数,用于指定从目标字符串的某个位置开始搜索(单位是字节)。
preg_match
函数返回匹配次数,它的值将是0次(不匹配)或 1 次,因为preg_match
在第一次匹配后将会停止搜索。
【示例】使用 preg_match() 函数搜索一个字符串。
1 |
|
输出结果为:
1 |
|
可以看到preg_match
在匹配到一次后就结束了。如果想匹配到所有的话,可以使用preg_match_all
。
1 |
|
输出结果为:
1 |
|
3.2 preg_replace
preg_replace
用于执行一个正则表达式的搜索和替换。其函数原型为:
1 |
|
参数说明如下:
- pattern : 要搜索的模式。可以使一个字符串或字符串数组。
- replacement : 用于替换的字符串或字符串数组。如果这个参数是一个字符串,并且 pattern 是一个数组,那么所有的模式都使用这个字符串进行替换。如果 pattern 和 replacement 都是数组,每个 pattern 使用 replacement 中对应的元素进行替换。如果 replacement 中的元素比 pattern 中的少,多出来的 pattern 使用空字符串进行替换。
- subject : 要进行搜索和替换的字符串或字符串数组。
- limit : 可选参数,每个模式在每个 subject 上进行替换的最大次数。默认是 -1(无限)。
- count : 可选参数,如果指定,将会被填充为完成的替换次数。
如果 subject 是一个数组,preg_replace() 返回一个数组,其他情况下返回一个字符串。
如果匹配被查找到,替换后的 subject 被返回,其他情况下返回没有改变的 subject。如果发生错误,返回 null 。
【示例】
1 |
|
【写在最后】
正则表达式虽好,但也不必要凡事尽皆正则。如果你仅仅想要检查某个字符串是否包含另外一个字符串,不要使用preg_match
,使用strpos
会更快。若凡是看到字符串就想正则,就会像这么一个段子:
1 |
|
参考
- [1] Wikipedia
- [2] runoob正则表达式教程
- [3] php官方文档-PCRE正则语法