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正则语法