Go to comments

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 可以出现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

)




Leave a comment 0 Comments.

Leave a Reply

换一张