php环视,正则表达式基本知识(php)

php-weizijiaocheng-253838.html等)的时候,在中间会有字符,但是字符长度不确定。这种情况下就需要使用+了: preg_match('/^]+>$/', ''); // => 1preg_match('/^]+>$/', ''); // => 1preg_match('/^]+>$/', '<>'); // => 0

如果说匹配一个双引号字符串,在双引号内,既可以出现字符也可以不出现字符。这种情况下就应该使用量词*。 preg_match('/^\"[^\"]*\"$/', '""'); // => 1preg_match('/^\"[^\"]*\"$/', '"abcd"'); // => 1

点号

点号.是与量词搭配比较多得一个字符。一般情况下,点号.可以匹配除了换行符\n以外的任意字符。 preg_match('/^.$/', 'z'); // => 1preg_match('/^.$/', '8'); // => 1preg_match('/^.$/', "\n"); // => 0

如果要使.能匹配的字符包含换行符\n,可以使用自制通配符\s\S或\w\W、\d\D。 preg_match('/^[\s\S]$/', "\n"); // => 1

使.能匹配的字符包含换行符\n的另外一种方法是指定正则匹配时使用单行模式。在php中,可以使用模式修饰符和预定义常量两种方法来指定单行模式。关于正则匹配的模式,后面会详细介绍。 preg_match('/(?s)^.$/', "\n"); // => 1 模式修饰符preg_match('/^.$/s', "\n"); // => 1 预定义常量

匹配优先量词、忽略优先量词

很多语言中,都可以使用/*...*/来注释代码,如果是一个支持语法高亮的文本编辑器就要能够提取/*...*/注释块。很easy的,我们可以写出如下正则表达式: $str = '/*this is a comment*/ /*this is another comment*/';preg_match('/\/\*.*\*\//', $str, $arr);echo $arr[0];/*this is a comment*/ /*this is another comment*/

可以看到,这个正则表达式出了点小问题,它把两个注释块匹配出来了,如果两个注释块中间有代码,那么代码也会匹配出来。

这是因为,我们介绍的*、+、?都是匹配优先量词(greedy quantifier,也称贪婪量词)。匹配优先量词是指在拿不准是否要匹配的时候,优先尝试匹配。因此,$str中间的*/ /*都被.*匹配了。

正则表达式中利用忽略优先量词来解决上述问题。与*、+、?对应的忽略优先量词的形式是*?、+?、??。忽略优先量词在不确定是否要匹配时选择“不匹配”的状态。还是以提取注释块的代码为例: preg_match('/\/\*.*?\*\//', $str, $arr);echo $arr[0];/*this is a comment*/

这样就达到了提取注释块的效果。 匹配优先量词 忽略优先量词 限定次数

* *? 可能出现,可能不出现,出现次数没有上限

+ +? 至少出现1次,没有上限

? ?? 出现0次或1次

{m,n} {m,n}? 出现次数大于等于m,小于等于n

{m,} {m,}? 至少出现m次,没有上限

{0,n} {0,n}? 出现0次-n次

php中有指定非贪婪匹配模式的模式修饰符和预定义常量,与忽略优先量词是一样的效果: // 默认贪婪匹配preg_match('/\/\*.*\*\//', $str, $arr); // => /*this is a comment*/ /*this is another comment*/ // 预定义常量 指定非贪婪匹配preg_match('/\/\*.*\*\//U', $str, $arr); // => /*this is a comment*/ // 模式修饰符 指定非贪婪匹配preg_match('/(?U)\/\*.*\*\//', $str, $arr); // => /*this is a comment*/ // 同时使用 忽略优先量词 和 预定义常量preg_match('/\/\*.*?\*\//U', $str, $arr); // => /*this is a comment*/ /*this is another comment*/// 同时使用 忽略优先量词 和 模式修饰符preg_match('/(?U)\/\*.*?\*\//', $str, $arr); // => /*this is a comment*/ /*this is another comment*/

量词的转义

*、+、?的转义比较简单,就是\*、\+、\?。主要是{m,n}形式的转义需要注意。 量词 转义 量词 转义 量词 转义

{n} \\{n} * \* *? \*\?

{m,n} \\{m,n} + \\+ +? \\+\?

{m,} \\{m,} ? \? ?? \?\?

{0,n} \\{0,n}

3.括号

分组

上一章介绍了量词,上一章的例子中量词都只能控制它前面的字符或字符组。那么量词能否控制连续的字符或字符组呢,如控制一个单词hello出现或者不出现。这就要用到正则表达式的分组功能(子表达式),使用圆括号(...)实现分组(子表达式)。 // 量词限定前面一个字符preg_match('/^hello?, world$/', 'hello, world'); // => 1preg_match('/^hello?, world$/', 'hell, world'); // => 1preg_match('/^hello?, world$/', ', world'); // => 0// 量词限定一个单词preg_match('/^(hello)?, world$/', 'hello, world'); // => 1preg_match('/^(hello)?, world$/', 'hell, world'); // => 0preg_match('/^(hello)?, world$/', ', world'); // => 1

多选结构

多选结构(alternative)的形式是(...|...),在括号内以竖线|分开多个子表达式,这些子表达式也叫多选分支(option)。

例如,匹配常见的11位手机号 // 匹配常见11位手机号preg_match('/(13[0-9]|15[0-356]|18[025-9])\d{8}/', '18521510001', $arr); // => 1

引用分组

正则表达式会保存每个(...)分组匹配的文本,这种功能叫捕获分组(capturing group)。在需要直接使用子表达式的时候非常有用 // 提取标签中的地址和描述文本preg_match('/(.*?)/', 'visit github', $arr);print_r($arr);/*Array( [0] => github [1] => github.com [2] => visit github)*/

正则表达式替换时也支持捕获分组。php中支持\num和$num的形式替换,但是num不能大于10;另一种形式${num}可以大于10。

例如,日期的替换 // 正则表达式替换preg_replace('/(\d{4})-(\d{2})-(\d{2})/', '$1年$2月$3日', '2015-08-25'); // => 2015年08月25日preg_replace('/(\d{4})-(\d{2})-(\d{2})/', '\1年\2月\3日', '2015-08-25'); // => 2015年08月25日

反向引用

在正则表达式内部引用之前的捕获分组匹配的文本叫反向引用(back-reference)。实测php支持\num形式的反向引用,不支持$num形式的反向引用

例如,利用反向引用匹配id相同的不同标签 // 匹配id为main的标签preg_match('/.*?/', '

hello, world', $arr); // => 1print_r($arr);/*Array( [0] =>

hello, world [1] => div)*/// 匹配id为main的标签preg_match('/.*?/', '

Hello, World', $arr); // => 1print_r($arr); /*Array( [0] =>

Hello, World [1] => p)*/

命名分组

数字编号的分组有时候不够直观,因此有些语言和工具的正则表达式提供了命名分组(named grouping)。

正则字符中(?P)来命名,(?P=name)来使用。preg_replace替换时不支持

非捕获分组

正则表达式默认会保存每个(...)匹配的文本,前面利用这个特性可以实现一些有用的功能。但是,有时候正则表达式比较复杂,(...)会出现的比较多,而此时仅仅是想实现分组或者多选的功能,而不需要捕获分组;同时,大量不需要的捕获分组可能会影响性能。

为了解决这种问题,正则表达式提供了非捕获分组(non-capturing group),它的形式是(?:...)。 // 捕获分组preg_match('/(13[0-9]|15[0-356]|18[025-9])\d{8}/', '18521510001', $arr); // => 1print_r($arr); /*Array( [0] => 18521510001 [1] => 185)*/// 非捕获分组echo preg_match('/(?:13[0-9]|15[0-356]|18[025-9])\d{8}/', '18521510001', $arr); // => 1print_r($arr); /*Array( [0] => 18521510001)*/

4.断言

正则表达式中的有些结构不匹配真正的文本,只负责判断在某个位置左/右侧的文本是否符合要求,这种结构称为断言(assertion)。常见的断言有三类:单词边界、行起始/结束位置、环视。

单词边界

单词边界(word boundary),记为\b。它匹配的是单词边界(一边是单词字符,另一边不是单词字符)的位置,而不是字符。 // 单词边界preg_match('/\b\w+\b/', 'word', $arr); // => 1print_r($arr);/*Array( [0] => word)*/// 匹配所有单词边界preg_match_all('/\b\w+\b/', 'hello, world', $arr); // => 2print_r($arr);/*Array( [0] => Array ( [0] => hello [1] => world ))*/

这类匹配位置而不匹配字符的元素叫做锚点(anchor),下一节要介绍的^、$等也是锚点。

行起始/结束位置

^:字符串的开始位置

$:字符串的结束位置 $str = 'first linesecond linelast line';// 字符串起始位置preg_match_all('/^\w+\b/', $str, $arr); // => 1print_r($arr);/*Array( [0] => Array ( [0] => first ))*/// 字符串结束位置preg_match_all('/\b\w+$/', $str, $arr); // => 1print_r($arr);/*Array( [0] => Array ( [0] => line ))*/

如果指定了多行模式(Multiline Mode),^、$分别可以匹配行起始位置、行结束位置。关于模式,将在下一章详细介绍。指定多行模式的方式是使用模式修饰符(?m):在正则表达式之前加上(?m);或者是预定义常量的方式:/.../m 。 // 多行模式 行起始位置// preg_match_all('/^\w+\b/m', $str, $arr); 是一样的效果preg_match_all('/(?m)^\w+\b/', $str, $arr); // => 3print_r($arr);/*Array( [0] => Array ( [0] => first [1] => second [2] => last ))*///多行模式 行结束位置// preg_match_all('/\b\w+$/m', $str, $arr); 是一样的效果preg_match_all('/(?m)\b\w+$/', $str, $arr); // => 3print_r($arr);/*Array( [0] => Array ( [0] => line [1] => line [2] => line ))*/

\A不论是普通模式还是多行模式,都匹配字符串起始位置

\Z、\z不论是普通模式还是多行模式,都匹配字符串结束位置

\Z与\z的区别在于最后字符串的末尾是行终止符的时候,\Z匹配行终止符之前的位置,\z则不管行终止符,只匹配“整个字符串的结束位置”。

这里用行终止符,而不用换行符的原因是不同操作系统的行终止符不同(windows\r\n,linux\n,mac\n)。

// \A 始终匹配字符串起始位置preg_match_all('/\A\w+\b/', $str, $arr); // => 1print_r($arr);/*Array( [0] => Array ( [0] => first ))*/preg_match_all('/(?m)\A\w+\b/', $str, $arr); // => 1print_r($arr);/*Array( [0] => Array ( [0] => first ))*/// \Z始终匹配行结束位置preg_match_all('/\b\w+\Z/', $str, $arr); // => 1print_r($arr);/*Array( [0] => Array ( [0] => line ))*/preg_match_all('/(?m)\b\w+\Z/', $str, $arr); // => 1print_r($arr);/*Array( [0] => Array ( [0] => line ))*/// \Z \z的区别$str = 'first linesecond linelast line';preg_match_all('/(?m)\b\w+\z/', $str, $arr); // => 0print_r($arr);/*Array( [0] => Array ( ))*/preg_match_all('/(?m)\b\w+\Z/', $str, $arr); // => 1print_r($arr);/*Array( [0] => Array ( [0] => line ))*/

环视

环视(look-around)用来“停在原地,四处张望”,它本身也不匹配任何字符,用来限定它旁边的文本满足某种条件。 名字 记法 含义

肯定顺序环视 (?=...) 向右看看,右边出现了环视中的内容才匹配

否定顺序环视 (?!...) 向右看看,右边不出现环视中的内容才匹配

肯定逆序环视 (?<=...) 向左看看,左边出现了环视中的内容才匹配

否定逆序环视 (?向左看看,左边不出现环视中的内容才匹配

上面的正则表达式中有两个环视结构,一个在开尖括号之前,表示在闭尖括号>之前向左看看,左边挨着的字符不能为/。

上面的正则表达式已经解决了匹配html中开标签的主要问题,只是其中的.*?还需要优化一下。需要解决的问题是: 有可能会有单引号'或双引号",它们都得成对出现

单引号对或双引号对之内可以有>字符,但是它们的外面不能有>字符

利用正则表达式的选择结构,可以写出下面的表达式,用于完善上面的问题。

])+(?

5.匹配模式

前面的内容中已经出现介过了单行模式、多行模式、非贪婪模式。匹配模式是指匹配时使用的规则。常用的匹配模式还有不区分大小写模式、注释模式。

在开始介绍具体的模式之前,先介绍php中模式的两种具体实现/.../{modifier}和...(?{modifier})...: 模式修饰符 /.../{modifier} ...(?{modifier})...

示例 /

.*/s

(?s).*

名称(php手册) 模式修饰符 模式内修饰符

名称(《正则指引》) 预定义常量 模式修饰符

作用范围 整个正则表达式 不在分组(子表达式)中时,对它后面的全部正则表达式起作用;如果在分组(子表达式)中,则对它分组中的剩余部分起作用。在没有分组,且放在整个正则表达式最前面的时候相当于/.../{modifier}

支持程度 支持所有模式修饰符 支持部分模式修饰符

其他编程语言 可能不支持 一般都支持

不区分大小写模式

在html中是不区分大小写的,例如和、、的作用是一样的。如果要从网页中提取,不使用匹配模式的表达式应该是这样:

由于标签只有两个字符,所以上面的写法还可以接受。但是如果标签是

php中文网:公益在线php培训,帮助PHP学习者快速成长!

Copyright 2014-2020 https://www.php.cn/ All Rights Reserved | 苏ICP备2020058653号-1e6cebb680dfe320dad7e62bd6442c3a6.gif

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值