PHP100 正则表达式
虽然学的是 PHP 中的正则表达式,
但是正则是一种通用的规则和语法,所以学好正则可以在更广的方向上应用正则的语法和规则,
而且正则是每个程序员必须具备的,可以帮我们减轻很多工作量
什么是正则?
在编写程序中,经常会遇到某些“复杂规则的字符串”,
比如邮件地址格式、手机号码等,
正则表达式就是用于描述这些的规则的语法。
正则主要有四个应用
1. 分割
2. 匹配(最重要)
3. 查找
4. 替换
PHP 中两个常用的正则函数
以 prel 语言为基础的正则函数,该函数返回布尔值
preg_match(mode, string subject, array matches);
1. mode 正则的语法,需要一个起始和结束符号,使用 / 反斜起始和结束,也可以使用 # 井号
2. string subject 需要正则的内容
3. array matches 正则的结果,不一定是一个结果,所以结果是一个数组的形式
以 POSIX 为基础的正则函数(Unix、Script),正则规则不需要起始和结束符号,该函数已经废弃了
ereg(mode, string subject, array regs);
正则表达式中的元素
1. 原子:普通字符 a-z A-Z _ 0-9、原子表、转义字符
2. 元字符:有特殊功能的字符,比如,#井号、*星号、^等特殊符号...
3. 模式修正符:增加提高正则的功能,让正则应用的更加广泛,系统内置的字符 i、m、S、U...
一、正则表达式中的“原子”
正则语法规则里面必须要包含一个原子
正则表达式中的原子:
1. 最常见的字符 a-z A-Z _ 0-9
2. 圆括号包起来的叫做单元符号 (abc)
3. 方括号包起来叫原子表,原子表中的 ^ 代表排除或相反内容 [abc] [^abc]
4. 转义字符串 \d、\D、\w、\W ...
1、常见的字符
最常见原子字符的匹配
a-z A-Z _ 0-9 是我们最常见的通用字符,直接写这些字符就可以匹配了,
比如匹配 a,写一个正则 /a/,就可以找一下整个字符串中有多少个 a
示例,
preg_match 函数
第一个参数,正则规则,需要一个起始和结束符号 #abc#
第二个参数,正则的内容是一个字符串,字符串里面包含了 abc,匹配成功
第三个参数,匹配结果是一个数组(如果匹配不成功,返回一个空数组 Array ( ) )
preg_match('#abc#', "sdfafabcdsdc", $arr); print_r($arr); // Array ( [0] => abc )
preg_match 函数返回一个布尔值,
写一个 if 条件语句,匹配成功输出数组的第1位 arr[0]
$mode = "/abc/"; $str = "sdfafabcdsdc"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; // 匹配成功 abc }else{ echo "匹配不成功"; }
/sbss/ 该规则匹配不成功,因为字符串中没有 sbss
$mode = "/sbss/"; $str = "sdfafabcdsdc"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; }else{ echo "匹配不成功"; // 匹配不成功 }
这就是最简单的原子匹配,匹配数字也是一样的
比如匹配数字 99
$mode = "/99/"; $str = "sdfafabcdsdc"; // 没有数字99,匹配不成功 $str = "sdfafabc9dsdc"; // 一个数字9,匹配不成功 $str = "sdfafabc99dsdc"; // 两个数字9,可以匹配成功 $str = "sdfafabc9ds9dc"; // 两个不挨着的数字9,匹配不成功
2. 单元符号
(abc) 圆括号的作用是
1. 作为一个整体模块,会把 abc 看做一个完整的内容。目前看不出太大的区别,后面到原子符的时候就明白了
2. 它放会在内存当中,下一次可以调用括号里面的正则内容
(abc) 作为一个整体,必须要有一个完整的 abc 才能匹配,
不会拆分着看,只出现 a、b、bc、ab,这些都是不能匹配的
$mode = "/(abc)/"; $str = "sdfafabc99dsdc"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; // 匹配成功 abc }else{ echo "匹配不成功"; }
3、原子表
[abc] 方括号括起来叫原子表,
与圆括号的完整体匹配相反,正则的字符串中出现了 a 或 b 或 bc,任何符合方括号中的有字母都可以匹配
[^abc] 原子表中的 ^ 代表排除或相反,
意思原子表中任何一个字符都不能匹配,只匹配除 abc 之外的内容,就是排除原子表中的内容
示例
可以匹配到一个 8,因为字符串中的数字 8,符合 [98] 原子表中的规则
$mode = "/[98]/"; $str = "hhhhhhh8jjjj9lllll"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".arr[]; // 匹配成功 9 }else{ echo "匹配不成功"; }
也就说是在整个字符串中,只要有一个原子表中的数字就可以匹配成功
如果原子表前加一个 ^ 符号,除了 9 和 8 以外的所有内容。因为没有贪婪匹配,只匹配出字符串的第一个字母 h
$mode = "/[^98]/"; $str = "hhhhhhh8jjjj9lllll"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; // 匹配成功 h }else{ echo "匹配不成功"; }
4、转义字符
转义字符其实就是对一些常用的规范做一个优化
转义字符 | |
\d | 包含所有数字 [0-9] |
\D | 除了所有数字以外 [^0-9] |
\w | 英文字符、下划线、数字 [z-aA-Z_0-9],包含了所有的常见字符 |
\W | 排除所有英文字符、下划线、数字 [^a-zA-Z_0-9] |
\s | 包含空白区域,如回车、换行、分页 [\f\n\r] |
... |
[0-9] 意思是只匹配字符串里面的数字
$mode = "/[0-9]/"; $str = "hhhhhhh8jjjj9lllll"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; // 匹配成功 8 }else{ echo "匹配不成功"; }
[0-9] 是常用的内容,可以写转义字符 \d
$mode = "/\d/"; $str = "hhhhhhh8jjjj9lllll"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; // 匹配成功 8 }else{ echo "匹配不成功"; }
[^0-9] 排查所有的数字,可以写大写的 \D
$mode = "/\D/"; $str = "hhhhhhh8jjjj9lllll";
\w 小写w,
匹配普通字符 [z-aA-Z_0-9],包括英文字母、数字、下划线
\W 大写W,
匹配排除了普通字符以外的特殊字符 @
$mode = "/\W/"; $str = "hhhhhhh8jj@#jj9lllll"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr; // 匹配成功 @ }else{ echo "匹配不成功"; }
\s 小写 s 匹配到了字符串里面的回车换行,虽然我们看不到回车换行
$mode = "/\s/"; $str = "hhhhhhh8jj@# jj9lllll"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr; // 匹配成功 }else{ echo "匹配不成功"; }
实际上,在字符串中加一个 \n 也可以匹配成功,它代表回车换行
$mode = "/\s/"; $str = "hhhhhhh8jj@#\njj9lllll";
Ps:
RegexTester(正则测试者) 微软的正则表达式测试工具
1. 下载地址 https://apps.microsoft.com/detail/9n0pbq11r3df?hl=zh-cn&gl=US
2. 需要安装微软的 NET Framework 2.0
2. 使用方法
Regex 写正则表达式,比如 [a-z]
Source 写正则的字符串内容,比如 sdfs2d3f4sd54fs6fSDFF
F5 键
Matches 正则出来的内容,所有的小写字母
二、正则表达式中的“元字符”
元字符可以理解成为特殊符号,也可以理解称为运算符号
元字符 | 作用 | |
* | 匹配前一个内容的0次1次或多次 | |
+ | 匹配前一个内容的1次或多次 | 但不能匹配0次,就像平时运算的 + 号,加 0 是没有意义的 |
? | 匹配前一个内容的0次或1次 | 跟上面的 * 、? 最大的区别是有次数限制,最多匹配1次 |
. | 匹配内容的0次1次或多次 | 但不包含回车换行 |
| | 选择匹配,类似 || 或运算符 | 因为这个运算符合是弱类型,导致 | 前面或后面不管是否加括号,都会做为整体匹配 |
^ | 匹配字符串首部内容 | |
$ | 匹配字符串尾部内容 | |
\b | 匹配单词边界,边界可以是空格或者特殊符号 | 主要用来匹配单词,国外认为匹配单词是一个重要的运算,所以放到了元字符这里 |
\B | 匹配除带单词边界以外内容 | |
{m} | 匹配前一个内容的重复次数为M次 | |
{m,} | 匹配前一个内容的重复次数大于等于M次 | |
{m,n} | 匹配前一个内容的重复次数M次到N次 | |
( ) | 合并整体匹配,并放入内存 | 在同一个正则表达式,可使用 \1 \2… 调出来依次使用 |
* 星号
规则中的 o* 是一体的,
1. 字母 o 只是做为和 * 星号匹配, /go*gle/ o 不算在正则表达式中的内容,星号 * 表示字母 o 可以出现0次1次或多次
2. 字符串中的 google 符合匹配规则
$mode = "/go*gle/"; $str = "abcdefgooglehijk"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; // 匹配成功 google }else{ echo "匹配不成功"; }
字母 o 出现0次1次或多次都可以匹配成功
$mode = "/go*gle/"; $str = "abcdefgglehijk"; // 出现的0次,匹配成功 ggle $str = "abcdefgoglehijk"; // 出现的1次,匹配成功 gogle $str = "abcdefgooooooglehijk"; // 出现多次,匹配成功 goooooogle
go*g*le 同样的字母 g 归属了 * 号,g 也可以出现0次1次或多次,不出现也可以匹配成功
$mode = "/go*g*le/"; $str = "abcdefgooooolehijk"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; // 匹配成功 gooooole }else{ echo "匹配不成功"; }
+ 加号
加号跟星号基本类似,但是不能0次,必须要有1次或多次
$mode = "/go+gle/"; $str = "abcdefgooglehijk"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; // 匹配成功 google }else{ echo "匹配不成功"; }
o+ o归属于加号了,正则规则中不存在o,字符串中 o 必须要出现一次,不出现匹配不成功
$mode = "/go+gle/"; $str = "abcdefgglehijk"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; }else{ echo "匹配不成功"; // 匹配不成功 }
换成星号可以0次,这是星号和加号的区别
字母 o 出现一次或多次都可以匹配成功
$mode = "/go+gle/"; $str = "abcdefgoglehijk"; // 出现一次匹配成功 gogle $str = "abcdefgoooooglehijk"; // 多个也可以匹配成功 gooooogle
? 问号
只能出现1次或0次,两个 o 匹配不成功
$mode = "/go?gle/"; $str = "abcdefgooglehijk"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; }else{ echo "匹配不成功"; // 匹配不成功 }
o? 匹配前一个字母 o 的0次或1次,也就是说最多只能出现1次
$mode = "/go?gle/"; $str = "abcdefgoglehijk"; // 出现一次匹配成功 gogle $str = "abcdefgglehijk"; // 没有也可以匹配成功 ggle
? 只有两种选择,
1次或0次,不能超过1次
. 点
*号、+号、?号前面要有一个字母,不然不知道匹配什么内容,
. 点不是匹配前一个内容,点本身作为内容,代表任意的字符,除了回车以外的任何字符
比如 .? 可以是任意字符的0次或1次
$mode = "/g.?gle/"; $str = "abcdefgjglehijk"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; // 匹配成功 gjgle }else{ echo "匹配不成功"; }
把 .? 问号换成 .* 星号,
.* 星号前面这点可以是任何内容,所有的内容,多少次都是可以匹配
$mode = "/g.*gle/"; $str = "abcdefg0000000000glehijk"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; // 匹配成功 g0000000000gle }else{ echo "匹配不成功"; }
只要符合这个 g.*gle 格式,中间任意内容都可以
$mode = "/g.*gle/"; $str = "abcdefg_____glehijk"; // 下划线可以匹配 g_____gle $str = "abcdefgdgdsdfglehijk"; // 任何内容都可以 gdgdsdfgle
.* 这个配合是一个经典的应用,任何字符串都可以通过
| 选择匹配
字符串中有 google 可以匹配
$mode = "/google|baidu/"; $str = "abcdgoogleefghijk"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; // 匹配成功 google }else{ echo "匹配不成功"; }
和原子表有点类似
原子表 [baidu] 是单个字符来匹配
google | baidu 前后作为整体单词(模块)匹配
把字符中的 google 换成 baidu 也可以匹配成功
$mode = "/google|baidu/"; $str = "abcdbaiduefghijk"; // 匹配成功 baidu
防止 sql 注入功能
$check = preg_match('/select|insert|update|delete|\'|\/\*|\*|\.\.\/|\.\/|union|into|load_file|outfile/', $sql); if ($check) { echo '有危险字符'; exit(); } else { return $sql; }
^ 首部匹配
^ 要求 google 在字符串开头出现,不是在开头出现所以匹配不成功
$mode = "/^google/"; $str = "abcdefgooglehijk"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; }else{ echo "匹配不成功"; // 匹配不成功 }
google 必须在字符串开头才能匹配成功
$mode = "/^google/"; $str = "googleabcdefhijk"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; // 匹配成功 google }else{ echo "匹配不成功"; }
$ 匹配字符串尾部内容
字符串必须以 google 结束
$mode = "/google$/"; $str = "abcdefhijkgoogle"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; // 匹配成功 google }else{ echo "匹配不成功"; }
^ 和 $ 一起使用,
以 abc 开始,以 google 结束,这两个不能连着,中间要有内容分开
$mode = "/^abc.*google$/"; $str = "abcdefhijkgoogle"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; // 匹配成功 abcdefhijkgoogle }else{ echo "匹配不成功"; }
匹配成功,整个字符串符合正则的规则
中间内容只能出现0次或1次,匹配就不成功了
$mode = "/^abc.?google$/"; $str = "abcdefhijkgoogle";
\b 匹配单词边界
is 前后必须是分界符的,前后有空格可以匹配
$mode = "/\bis\b/"; $str = "what is this"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; // 匹配成功 is }else{ echo "匹配不成功"; }
is 后面没有分割匹配不成功
$mode = "/\bis\b/"; $str = "what is";
横杠可以作为分界符
$mode = "/\bis\b/"; $str = "what is-this"; // 用横杠作为分界符也可以匹配 $str = "whatisthis"; // 连起来就不能匹配了
\B 不允许有分界符
is 前后没有分割符匹配成功
$mode = "/\Bis\B/"; $str = "whatisthis"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; // 匹配成功 is }else{ echo "匹配不成功"; }
{m}
限制前面的字母 o 必须出现 1 次
$mode = "/go{1}gle/"; $str = "abcdefgoglehijk"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; // 匹配成功 gogle }else{ echo "匹配不成功"; }
出现 2 次匹配不成功
$mode = "/go{1}gle/"; $str = "abcdefgooglehijk";
限制出现 5 个字母
$mode = "/go{5}gle/"; $str = "abcdefgoooooglehijk"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; // 匹配成功 gooooogle }else{ echo "匹配不成功"; }
{m,}
至少要有 5 个字母 o,不能少于 5 个,多着不限 6 个字母匹配成功
$mode = "/go{5,}gle/"; $str = "abcdefgooooooglehijk"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; // 匹配成功 goooooogle }else{ echo "匹配不成功"; }
{m,n}
2 到 5 之间的都可以匹配成功,中间有 4 个字母 o 可以匹配成功
$mode = "/go{2,5}gle/"; $str = "abcdefgooooglehijk"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; // 匹配成功 goooogle }else{ echo "匹配不成功"; }
超过 5 个匹配不成功
$mode = "/go{2,5}gle/"; $str = "abcdefgoooooglehijk"; // 5个字母可以匹配成功 gooooogle $str = "abcdefgooooooglehijk"; // 6个字母超出了范围,匹配不成功
( ) 括号
abc 作为整体匹配,中间必须出现的 abc。这个上节课就学过了,下面看如何调用
$mode = "/go(abc)gle/"; $str = "abcdefgoabcglehijk"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; // 匹配成功 goabcgle }else{ echo "匹配不成功"; }
同一个正则表达式中,调用括号里面的内容,
第一个括号作为 \\1 在内存中保存,
\\1 相当于又把 abc 作为整体调用了,也就是 \\1 对应的就是 abc
$mode = "/go(abc)g\\1le/"; $str = "abcdefgoabcgabclehijk"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; // 匹配成功 goabcgabcle }else{ echo "匹配不成功"; }
括号可以在年月日格式时候限制一下
前面用 - 分割后面也用 - 分割
前后用 / 分割后也用 / 分割
$mode = "/2009(.*)02\\1(15)/"; // $str = "2009-02-15"; $str = "2009/02/15"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; // 匹配成功 2009-02-15 }else{ echo "匹配不成功"; }
\\1(15) 这里用括号,这样 \\115 都是数字会认为是内存中的第 115 个括号
日期的数字格式用正则限制
$mode = "/[0-9]{2,4}(.*)[0-9]{2,4}\\1[0-9]{2,4}/"; $str = "2010/02/15"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; // 匹配成功 2010/02/15 }else{ echo "匹配不成功"; }
0-9 数字可以用 \d
$mode = "/\d{2,4}(.*)\d{2,4}\\1\d{2,4}/";
三、正则中的运算顺序
跟普通的数学的逻辑运算顺序是一样的,
在没有特殊的符号情况下,依然遵循从左到 → 右的运算规则,
除了运算顺序的规则,还有符号的优先级
符号的优先级
符号 | 优先级 |
( ) | 圆括号因为是内存处理所以最高 |
* ? + {} | 重复匹配内容其次 |
^ $ \b | 边界处理第三 |
| | 条件处理第四 |
最后按照运算顺序计算匹配 |
( ) 圆括号括起来的内容,是正则表达式中优先处理的
因为首先要读入内存中,才能在正则中第一次、第二次...调用括号里面的规则
* ? + {} 重复性的内容,
如果先用下面边界符,把边界的分开后,在去重复可能会出现错误,所以重复的排第二位
也就是首先确定有哪些重复的内容,然后在限定的边界符
\b 整个单词边界
^ $ 整个正则表达式的开始匹配,或是结束匹配
第二课学过,条件处理 | 会把左边和右边的内容,作为一个完整内容判断,
也就是说上面的功能都处理完后,然后将结果进行判断,
意思是前面一段正则,后面一段正则,两段正则都处理完了,在通过条件判断,这两个结果是不是得到内容的匹配
最后按照顺序依次继续计算匹配
四、模式修正符
模式修正符是对“正则表达式功能”的增强和补充
常用的修正符
修正符 | 作用 |
下面的字母是小写 | |
i | 正则内容在匹配时候不区分大小写(默认是区分的) |
m | 在匹配首内容或者尾内容时候采用多行识别匹配 |
s | 将转义回车取消是为单行匹配如. 匹配的时候 |
x | 忽略正则中的空白 |
e | 该修正符已经废弃了 |
下面三个字母是大写 | |
A | 强制从头开始匹配 |
D | 强制$匹配尾部无任何内容 \n |
U | 禁止贪婪匹配 只跟踪到最近的一个匹配符并结束,常用在采集程序上的正则表达式 |
i
默认是区分的,模式修正符 i 不区分大小写
$mode = "/[a-z]/i"; $str = "B"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; // 匹配成功 B }else{ echo "匹配不成功"; }
m
主要是增强 ^符号 和 $符号 的功能,
这两个 ^ 和 $ 符号是匹配整个段落内容的开始和结尾,不管段落分了多少行或是回车,只匹配整个段落的开始和结束,
如果使用修正符 m,符号 ^ 不仅仅是匹配整个段落的开始,而是匹配每一行的开始
比如,^ 符号要求段落以 aaa 开头,字符串不是以 aaa 开头匹配不成功
$mode = "/^aaa/"; $str = "12345\naaa6789"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; }else{ echo "匹配不成功"; // 匹配不成功 }
字符串中 \n 的功能是回车换行,所以源码的格式中的 aaa 在第二行的首位置
12345
aaa6789
因为 aaa 出现在第二行的开头,加上修正符 m 可以匹配成功
$mode = "/^aaa/m"; $str = "12345\naaa6789"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; // 匹配成功 aaa }else{ echo "匹配不成功"; }
结尾也一样,
修正符 m 不管有几行回车,只要有一行的结尾出现了 aaa 就可以匹配成功
$mode = "/aaa$/m"; $str = "12345aaa\n6789"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; // 匹配成功 aaa }else{ echo "匹配不成功"; }
整个段落的结尾没有 aaa,在源码格式中 aaa 出现在第一行尾部,所以匹配成功
12345aaa
6789
s
小写 s 可以将段落中的回车换行取消,
比如 .* 可以匹配所有的任何内容,但是不包括回车的,
但是有时候段落里面有回车,修正符 s 可以把段落中的回车转义取消
下面的字符串的源码格式有换行,而 (.*) 是不包括回车换行的
aaabbb
cccddd
eeefffggg
修正符 s 可以把回车取消,实际是转换成空格
```php $mode = "/aaa(.*)ggg/s"; $str = "aaabbb\ncccddd\neeefffggg"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; // 匹配成功 aaabbb cccddd eeefffggg }else{ echo "匹配不成功"; } ```
s 增强了 .* 的功能,匹配大量的 html 代码做采集程序的时候可以上
x
忽略正则表达式当中的空白,
注意不是正则字符串的空白,是正则表达式中的空白
正则中 cc c 有空格匹配不到,x 可以忽略掉正则表达式中的空格
$mode = "/cc c/x"; $str = "aaabbbcccdddeee"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; // 匹配成功 ccc }else{ echo "匹配不成功"; }
上节课日期正则,可以使用 x 忽略正则表达式中的空格,又不影响正则
$mode = "/2009(.*)02\\1 15/x"; $str = "2009-02-15"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; // 匹配成功 2009-02-15 }else{ echo "匹配不成功"; }
A
这里改用 preg_match_all() 全局匹配函数,
以 333 开头,并且修正符 m 多行匹配,可以匹配出两个 333
$mode = "/^333/m"; $str = "333aaa\n333bbbcccdddeee"; if(preg_match_all($mode, $str, $arr)){ print_r($arr[0]); // Array ( [0] => 333 [1] => 333 ) }else{ echo "匹配不成功"; }
修正符 A 强制必须从整个段落开头进行匹配,只能匹配出开头的一个 333,实际上 m 的功能就消失了,下一行不起作用了
$mode = "/^333/mA"; $str = "333aaa\n333bbbcccdddeee"; if(preg_match_all($mode, $str, $arr)){ print_r($arr[0]); // Array ( [0] => 333 ) }else{ echo "匹配不成功"; }
字符串开头没有 333 匹配不成功
$mode = "/^333/mA"; $str = "aaa\n333bbbcccdddeee";
D
段落尾部是 eee 可以匹配成功,根据的是段落的内容不包括 \n 回车
$mode = "/eee$/"; $str = "aaa\n333bbbccc\ndddeee\n"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; // 匹配成功 eee }else{ echo "匹配不成功"; }
加上修正符 D 严格要求段落后面必须是干净的,有回车匹配失败。包括 A 也是前面的内容必须是干净
$mode = "/eee$/D"; $str = "aaa\n333bbbccc\ndddeee\n"; if(preg_match($mode, $str, $arr)){ echo "匹配成功 ".$arr[0]; }else{ echo "匹配不成功"; // 匹配不成功 }
U
不加修正符 U,默认是贪婪匹配
$mode = "/<b(.*)b>/"; $str = "大吊车<b>真厉害</b>,轻轻的<b>一抓</b>就起来"; if(preg_match($mode, $str, $arr)){ echo $arr[0]; // <b>真厉害</b>,轻轻的<b>一抓</b> }else{ echo "匹配不成功"; }
U 的作用只跟踪到近匹配的一个字符
$mode = "/<b(.*)b>/U"; $str = "大吊车<b>真厉害</b>,轻轻的<b>一抓</b>就起来"; if(preg_match($mode, $str, $arr)){ echo $arr[0]; // <b>真厉害</b> }else{ echo "匹配不成功"; }
五、PHP中的正则函数
全局匹配
preg_match_all( string pattern, string subject, array matches [, int flags )
前两个参数和之前一样“正则模块”、“正则的字符串”,第三个参数正则的结果,该结果是二维数组
$str = "网站名称{title}作者{author},内容是{content}以及其他"; $mode = "/{(.*)}/U"; preg_match_all($mode, $str, $arr); print_r($arr);
Array(
[0] => Array(
[0] => {title}
[1] => {author}
[2] => {content}
),
[1] => Array(
[0] => title
[1] => author
[2] => content
)
)
替换功能,类似 str_replace 字符串替换
preg_replace( mixed pattern, mixed replacement, mixed subject [, int limit] )
正则替换有四种用法
1. 正则表达式替换
2. 还可以替换“正则表达式数组”
3. 通过修正符 e 将替换的内容先运算在替换
4. 第四参数是可选的,功能是替换的次数
正则表达式替换
参数一:正则模块
参数二:所要替换的内容
参数三:所要替换的字符串
$str = "青青的{title}上生活着{author},直到{content}搬到对岸的森林..."; $mode = "/{(.*)}/U"; echo preg_replace($mode, '中文', $str); // 青青的中文生活着中文,直到中文搬到对岸的森林...
如果用字符串 str_replace 方法要替换三次
$str = "青青的{title}上生活着{author},直到{content}搬到对岸的森林..."; $str = str_replace("{title}", "草原", $str); $str = str_replace("{author}", "喜洋洋", $str); $str = str_replace("{content}", "灰太狼", $str); echo $str; // 青青的草原生活着喜洋洋,直到灰太狼搬到对岸的森林...
提示:
不仅仅可以替换正则表达式,也可以替换正则表达式数组
1. 替换内容可以是一个正则也可以是数组正则
2. 替换内容可以通过修正符 e 来解决替换执行内容
替换“正则表达式数组”的意思是,将相应的正则对应替换成不同的内容
$str = "青青的{title}上生活着{author},直到{content}搬到对岸的森林..."; $mode = array("/{title}/", "/{author}/", "/{content}/"); $replace = ["草原", "喜洋洋", "灰太狼"]; echo preg_replace($mode, $replace, $str); // 青青的草原生活着喜洋洋,直到灰太狼搬到对岸的森林...
匹配出来的英文字符,先不进行替换,先对字符进行某种计算,比如 md5 加密,然后在进行替换
$str = "青青的a上生活着b,直到c搬到对岸的森林..."; $mode = "/([a-z])/i"; // 括起来下面可以取到内存中的正则 echo preg_replace($mode, "md5(\\1)", $str); // 青青的md5(a)上生活着md5(b),直到md5(c)搬到对岸的森林...
$mode = "/([a-z])/ie"
加上修正符 e 可以按照某种计算方式运行
但是 php5.5 以上版本 e 已废弃了
https://www.cnblogs.com/yangykaifa/p/6839586.html
可以使用正则替换过滤敏感词
$str = "青青的CNM上生活着该死,直到孙子搬到对岸的森林"; $mode = "/CNM|该死|孙子/"; echo preg_replace($mode, "***", $str); // 青青的***上生活着***,直到***搬到对岸的森林
还有第四个可选参数,功能是替换的次数
echo preg_replace($mode, "***", $str, 1); // 青青的***上生活着该死,直到孙子搬到对岸的森林 echo preg_replace($mode, "***", $str, 2); // 青青的***上生活着***,直到孙子搬到对岸的森林 echo preg_replace($mode, "***", $str, 3); // 青青的***上生活着***,直到***搬到对岸的森林
正则分割,功能类似 explode 切割函数
preg_split ( string pattern, string subject [, int limit [, int flags]] )
通过多个符号分割
$str = "async,异步,axios,ajax-fecth.promise"; // 中文全角逗号转英文逗号, // 因为中文逗号会认为有一个回车,导致替换后数组有一个空位 echo $str = str_replace(',', ',', $str); $mode = "/[,.-]/"; $arr = preg_split($mode, $str); print_r($arr);
(
[0] => async
[1] => axios
[2] => ajax
[3] => fecth
[4] => promise
)