PHP正则表达式

1.什么是正则表达式

正则表达式(Regular Expression,regexp)是一种描述字符串结构的语法规则,是一个特定的格式化模式,用于验证各种字符串是否匹配(Match)这个特征,进而实现高级的文本查找、替换、截取内容等操作。例如,若想要使Apache服务器解析PHP文件,需要在Apache的配置文件中添加能够匹配出以“.php”结尾的配置“.php8.PHP正则表达式 - 图1”就是一个简单的正则表达式。

正则表达式在发展过程中出现了多种形式,一种是POSIX规范兼容的正则表达式,包括基本语法BRE(Base Regular Expression)和扩展语法ERE(Extended Regular Expression)两种规则,用于确保操作系统之间的可移植性,但最终没有成为标准只能作为一个参考。另一种是当Perl(一种功能丰富的编程语言)发展起来后,衍生出来了PCRE(Perl Compatible Regular Expressions,Perl兼容正则表达式)库,使得许多开发人员可以将PCRE整合到自己的语言中,PHP中也为PCRE库的使用提供了相应的函数。

如何使用正则表达式

在PHP的开发中,经常需要根据正则匹配模式完成对指定字符串的搜索和匹配。此时,可使用PHP提供的PCRE相关内置函数。preg_match()函数是最常用的一个函数,下面介绍此函数的几种常见用法。

1.执行匹配

preg_match()函数的第1个参数是正则表达式,第2个参数是被搜索的字符串,示例如下。

  1. $result = preg_match('/web/','phpwebphpweb');
  2. var_dump($result); //输出:int(1)

在上述示例中,“/web/”中的“/”是正则表达式的定界符。当函数匹配成功时返回1,匹配失败时返回0,如果发生错误则返回false。由于被搜索字符串中包含“web”,因此函数的返回值为1。

值得一提的是,PHP中的PCRE正则函数都需要在正则表达式的前后加上定界符“/”,并且定界符可以自己设置,只要保持前后一致即可。

2.获取匹配结果

preg_match()函数的第3个参数用于以数组形式保存匹配到的结果,示例如下。

  1. preg_match('/web/','phpwebphpweb',$matches);
  2. print_r($matches); //输出:Array ( [0] => web )

需要注意的是,preg_match()函数在正则匹配时,只要匹配到符合的内容,就会停止继续匹配。因此,虽然示例中字符串有两个“bad”,但在匹配结果中只有一个。

3.设置偏移量

  1. preg_match('/web/','phpwebphpweb',$matches,PREG_OFFSET_CAPTURE);
  2. print_r($matches); //输出:Array ( [0] => Array ( [0] => web [1] => 3 ) )

示例中preg_match()的第4个参数设置为“PREG_OFFSET_CAPTURE”,表示将第一次匹配到指定规则的内容所在位置的偏移量添加到$matches中,待查字符串的开始位置从0开始计算。例如,字符串“abdbc”中的“a”的偏移量是0,“c”的偏移量是4。

通过打印结果可以看出,preg_match()根据正则的规则在字符串“preg_match(‘/web/‘,’phpwebphpweb’,$matches,PREG_OFFSET_CAPTURE);”中匹配到了指定的字符串“web”,且“web”字符的位置偏移量为3。

2.正则表达式快速入门

1.正则表达式的组成

在PHP的PCRE函数中,一个完整的正则表达式是由4部分内容组成的,分别为定界符、元字符、文本字符和模式修饰符。其中,元字符是具有特殊含义的字符,如“^”“.”或“*”等,文本字符就是普通的文本,如字母和数字等。模式修饰符用于指定正则表达式以何种方式进行匹配,如i表示忽略大小写,x表示忽略空白字符等,具体示例如下所示。

  1. preg_match('/.*it/','ITHeima'); // 匹配结果:0
  2. preg_match('/.*it/i','ITHeima'); //匹配结果:1

在上述示例中,“._”用于匹配任意字符,因此正则表达式“/._it/”可以匹配任意含有“it”的字符串,如“it”“itheima”等。当添加模式修饰符“i”时,表示可匹配的内容忽略大小写,如所有含“IT”“It”“iT”和“it”的字符串都可以。需要注意的是,在编写正则表达式时,元字符和文本字符在定界符内,模式修饰符一般标记在结尾定界符之外。

正则表达式定义了许多元字符用于实现复杂匹配,而若要匹配的内容是这些字符本身时,就需要在前面加上转义字符“\”,如“^”和“\”等,具体示例如下。

  1. preg_match('/\^/','123^456',$matches);
  2. print_r($matches); //输出结果:Array ( [0] => ^ )
  3. preg_match('/\*/','123*456',$matches);
  4. print_r($matches); //输出结果:Array ( [0] => * )
  5. preg_match('/\\\/','123\456',$matches);
  6. print_r($matches); //输出结果:Array ( [0] => \ )

在上述示例中,由于PHP的字符串存在转义问题,因此在代码中书写的“\”实际只保存了一个“\”。从输出结果可以看出,利用正则表达式的转义字符“\”成功匹配出了特殊字符。

2.获取所有匹配结果

在PHP中,preg_match_all()函数的功能与preg_match()函数类似,区别在于preg_match()函数在第一次匹配成功后就停止查找,而preg_match_all()函数会一直匹配到最后才停止,获取到所有相匹配的结果。下面介绍preg_match_all()函数的几种常用的使用方法。

1.执行匹配

利用preg_match_all()执行正则表达式匹配,示例代码如下。

  1. $result = preg_match_all('/web/','phpwebphpweb');
  2. var_dump($result); //输出: int(2)

从上述示例可知,preg_match_all()函数的第1个参数表示正则表达式,第2个参数是被搜索的字符串。该函数执行成功时返回匹配的次数,如果返回0表示没有匹配到;当发生错误时返回false。

2.获取匹配结果

preg_match_all()函数的第3个参数可以保存所有匹配到的结果,具体示例如下。

  1. preg_match_all('/web/','phpwebphpweb',$matches);
  2. print_r($matches); //输出:Array ( [0] => Array ( [0] => web [1] => web ) )

值得一提的是,preg_match_all()函数还有第4个参数,用于设置匹配结果在第3个参数中保存的形式,默认值为PREG_PATTERN_ORDER,表示在结果数组的第1个元素$matches[0]中保存所有匹配到的结果;如果将值设置为PREG_SET_ORDER,表示结果数组的第1个元素保存第1次匹配到的所有结果,第2个元素保存第2次匹配到的所有结果,以此类推。

3.正则表达式语法

1.定位符与选择符

1.定位符

在程序开发中,经常需要确定字符在字符串中的具体位置。例如,匹配字符串的头部或尾部。利用正则表达式元字符中的定位符可以实现字符定位,具体示例如下。

  1. <?php
  2. $subject = "It's a nice day today";
  3. //匹配字符串开始的位置
  4. preg_match('/^It/', $subject,$matches);
  5. print_r($matches); //输出结果:Array ( [0] => It )
  6. //匹配字符串开始的位置
  7. preg_match('/today$/', $subject,$matches);
  8. print_r($matches); //输出结果:Array ( [0] => today )
  9. ?>

从上述示例可以看出,正则表达式中定位符“^”可用于匹配字符串开始的位置,定位符“$”用于匹配字符串结尾的位置。

2.选择符

若要查找的条件有多个,只要其中一个满足即可成立时,可以用选择符“|”。该字符可以理解为“或”,具体使用示例如下。

  1. <?php
  2. $subject = "123456";
  3. preg_match_all('/34|56|78/', $subject,$matches);
  4. print_r($matches); //输出结果:Array ( [0] => Array ( [0] => 34 [1] => 56 ) )
  5. ?>

从以上示例可以看出,只要待匹配字符串中含有选择符“|”设置的内容就会被匹配出来。

2.字符范围与反斜线

1.字符范围

在正则表达式中,对于匹配某个范围内的字符,可以用中括号“[]”和连字符“-”来实现。且在中括号中还可以用反义字符“^”,表示匹配不在指定字符范围内的字符。下面以使用preg_match_all()函数匹配“AbCd”为例,具体的用法如下表所示。

示例 说明 匹配结果
[abc] 匹配字符a、b、c b
[^abc] 匹配字符a、b、c以外的字母 A、C、d
[B-Z] 匹配字母B-Z范围内的字符 C
[^a-z] 匹配字母a-z范围内的字符 A、C
[a-zA-Z0-9] 匹配大写字母、小写字母和数组0-9范围内的字符 A、b、C、d

需要注意的是,字符“-”在通常情况下只表示一个普通字符,只有在表示字符范围时才作为元字符来使用。“-”连字符表示的范围遵循字符编码的顺序,如“a-Z”“z-a”“a-9”都是不合法的范围。

2.反斜线

在正则表达式中,“\”除了前面讲解的可作转义字符外,还具有其他功能。例如,匹配不可打印的字符、指定预定义字符集等。反斜线的常用功能如下表所示。

8.PHP正则表达式 - 图2

从表中可以看出,利用预定的字符集可以很容易完成某些正则匹配。例如,大写字母、小写字母和数字可以使用“\w”直接表示,若要匹配0到9之间的数字可以使用“\d”表示,有效的使用反斜线的这些功能可以使正则表达式更加简洁,便于阅读。

3.字符的限定与分组

1.点字符和限定符

点字符“。”用于匹配一个任意字符,限定符(?、+、*、{})用于匹配某个字符连续出现的次数。关于点字符和限定符的详细说明如下表所示。

8.PHP正则表达式 - 图3

2.贪婪与懒惰匹配

当点字符和限定符连用时,可以实现匹配指定数量范围的任意字符。例如,“^pre.*end$”可以匹配以pre开始到end结束,中间包含零个或多个任意字符的字符串。正则表达式在实现指定数量范围的任意字符匹配时,支持贪婪匹配和惰性匹配两种方式。

所谓贪婪表示匹配尽可能多的字符,而惰性表示匹配尽可能少的字符。在默认情况下是贪婪匹配,若想要实现惰性匹配,需在上一个限定符的后面加上“?”符号。具体示例如下所示。

  1. <?php
  2. //贪婪匹配
  3. $subject = "phphphph";
  4. preg_match('/p.*h/', $subject,$matches);
  5. print_r($matches); //输出结果:Array ( [0] => phphphph )
  6. //懒惰匹配
  7. preg_match('/p.*?h/', $subject,$matches);
  8. print_r($matches); //输出结果:Array ( [0] => ph )
  9. ?>

从上述示例可以看出,贪婪匹配时,会获取最先出现的p到最后出现的h,即可获得匹配结果为“phphphph”;懒惰匹配时,会获取最先出现的p到最先的出现的h,即可获取匹配结果“ph”。

3.括号字符

在正则表达式中,括号字符“()”有两个作用:一是改变限定符的作用范围;二是分组。接下来,针对这两个作用分别进行讲解。

1.改变限定符的作用范围

改变作用范围前:

  1. 正则表达式:firm|sh
  2. 可匹配的结果:firmsh

改变作用范围后:

  1. 正则表达式:fi(rm|sh)
  2. 可匹配的结果:firmfish

从上述示例可知,小括号实现了匹配firm和fish,而如果不使用小括号,则变成了firm和sh。

2.分组

分组前:

  1. 正则表达式:bana{2}
  2. 可匹配的结果:banaa

分组后:

  1. 正则表达式:ba(na){2}
  2. 可匹配的结果:banana

在上述示例中,未分组时,表示匹配2个a字符;而分组后,表示匹配2个“na”字符串。

4.模式修饰符

在PHP正则表达式的定界符外,还可以使用模式修饰符,用于进一步对正则表达式进行设置。其中,常用的模式修饰符如下表所示。

8.PHP正则表达式 - 图4

若要忽略匹配字符的大小写,除了使用选择符“|”和中括号“[]”外,还可以直接在定界符外添加i模式符;若要忽略目标字符串中的换行符,可以使用模式修饰符s等。除此之外,模式修饰符还可以根据实际需求多个组合在一起使用。例如,既要忽视大小写又要忽视换行,则可以使用直接使用is。在编写多个模式修饰符时没有顺序要求。

4.正则表达式运算符优先级

PHP中常用的正则表达式运算符优先级由高到低的顺序如下表所示。

8.PHP正则表达式 - 图5